Related
im using fastapi and python and need to check in dictionary if value is null.
i have a json like this:
{
"id": null,
"first_name": null,
"last_name": null,
"email": null,
"user_id": null,
"active": null
},
using a query to DB.
my dictionary sting is
user = {"id": n['id'], "first_name": n['first_name'], "last_name": n['last_name'],
"email": n['a_email'], "user_id": n['user_id'], "active": n['active']}
this values "active": null is empty in the table. How i can use if-else in python to check, if unique_id is null i need to write in my json only
{null}
but if
"unique_id": inc['a_unique_id'] have a value for example, 1, i need to get all info from this row:
{
"id": 1 ,
"first_name": "username",
"last_name": "userlastname",
"email": ""email#email.com,
"user_id": userlogin,
"active": 0
},
final json i need to get should looks like this
--for row with info ---
{
"id": 1 ,
"first_name": "username",
"last_name": "userlastname",
"email": ""email#email.com,
"user_id": userlogin,
"active": 0
},
for row with null values
{null}
i tried something like this
if n['id'] == "null":
user = {"user": "NULL"}
else:
user= {"id": n['id'], "first_name": n['first_name'], "last_name": n['last_name'],
"email": n['email'], "user_id": n['user_id'], "active": n['active']}
but this dont work like i need
Python's None is equivalent to JSON's null.
So what you should do is the following:
if n['id'] is None:
user = None
else:
user= {"id": n['id'],
"first_name": n['first_name'],
"last_name": n['last_name'],
"email": n['email'],
"user_id": n['user_id'],
"active": n['active']}
I am new to python dict, and have question regarding append value to key. Sample python dictionary is like below. How can I append values if key-value pair, ID & time are same? Please see expected result below. Tried append(), pop(), update(), and couldn't get expected result. Appreciate any help.
{
"Total": [
{
"ID": "ID_1000",
"time": 1000,
"name": {
"first_name": "John",
"last_name": "Brown"
}
},
{
"ID": "ID_5000",
"time": 5000,
"name": {
"first_name": "Jason",
"last_name": "Willams"
}
},
{
"ID": "ID_5000",
"time": 5000,
"name": {
"first_name": "Mary",
"last_name": "Jones"
}
},
{
"ID": "ID_1000",
"time": 1000,
"name": {
"first_name": "Michael",
"last_name": "Kol"
}
}
]
}
Below is the expected result.
{
"Total": [
{
"ID": "ID_1000",
"time": 1000,
"name": [
{
"first_name": "John",
"last_name": "Brown"
},
{
"first_name": "Michael",
"last_name": "Kol"
}
]
},
{
"ID": "ID_5000",
"time": 5000,
"name": [
{
"first_name": "Jason",
"last_name": "Willams"
},
{
"first_name": "Mary",
"last_name": "Jones"
}
]
}
]
}
One option is use a intermediate dictionary with your ids as keys.
Note that this code do not manage the time data, because is not clear if you want to add or what is expected.
import json
values = {
"Total": [
{
"ID": "ID_1000",
"time": 1000,
"name": {
"first_name": "John",
"last_name": "Brown"
}
},
{
"ID": "ID_5000",
"time": 5000,
"name": {
"first_name": "Jason",
"last_name": "Willams"
}
},
{
"ID": "ID_5000",
"time": 5000,
"name": {
"first_name": "Mary",
"last_name": "Jones"
}
},
{
"ID": "ID_1000",
"time": 1000,
"name": {
"first_name": "Michael",
"last_name": "Kol"
}
}
]
}
# first create a dictionary with the ids as keys
consolidated_names = {}
for total_value in values["Total"]:
id = total_value["ID"]
if id not in consolidated_names:
consolidated_names[id] = [total_value["name"]]
else:
consolidated_names[id].append(total_value["name"])
# then create the structure that you want
processed_values = []
for id in consolidated_names:
processed_values.append({"ID": id, "name": consolidated_names[id]})
print(json.dumps({"Total": processed_values}, indent=4))
Result:
{
"Total": [
{
"ID": "ID_1000",
"name": [
{
"first_name": "John",
"last_name": "Brown"
},
{
"first_name": "Michael",
"last_name": "Kol"
}
]
},
{
"ID": "ID_5000",
"name": [
{
"first_name": "Jason",
"last_name": "Willams"
},
{
"first_name": "Mary",
"last_name": "Jones"
}
]
}
]
}
i have a sample json file from a webhook response and i will want to extract just two data set from the JSON how can i do that using python. assuming i want to get the subscription code, and plan code values. thanks in anticipation
"event": "subscription.create",
"data": {
"domain": "test",
"status": "active",
"subscription_code": "SUB_vsyqdmlzble3uii",
"amount": 50000,
"cron_expression": "0 0 28 * *",
"next_payment_date": "2016-05-19T07:00:00.000Z",
"open_invoice": null,
"createdAt": "2016-03-20T00:23:24.000Z",
"plan": {
"name": "Monthly retainer",
"plan_code": "PLN_gx2wn530m0i3w3m",
"description": null,
"amount": 50000,
"interval": "monthly",
"send_invoices": true,
"send_sms": true,
"currency": "NGN"
},
"authorization": {
"authorization_code": "AUTH_96xphygz",
"bin": "539983",
"last4": "7357",
"exp_month": "10",
"exp_year": "2017",
"card_type": "MASTERCARD DEBIT",
"bank": "GTBANK",
"country_code": "NG",
"brand": "MASTERCARD"
},
"customer": {
"first_name": "BoJack",
"last_name": "Horseman",
"email": "bojack#horsinaround.com",
"customer_code": "CUS_xnxdt6s1zg1f4nx",
"phone": "",
"metadata": {},
"risk_action": "default"
},
"created_at": "2016-10-01T10:59:59.000Z"
}
}
You can use the built-in json library. For example:
import json
#if your json is in file
dict_from_file = json.load(open("foo.json"))
#if your json is in a string
dict_from_string = json.loads(string)
The following json (otherwise known as 'Cus_data') is what I am working on deciphering with the pandas.io.json.json_normalize package.
I can get within the json at a base level by
cus_data = json_normalize(cus_data, 'data')
or
cus_data = json_normalize(cus_data['data'], max_level=1)
....Not sure which is best practice
I can't seem to figure out how to enter "Sources", "subscriptions","plan" or any sub categories. I'm sure this is basic but I cannot seem to grasp the concept of drilling down using this package under pandas. Any input or tips would be great on how to look at json from the outside like this.
{
"data": [
{
"account_balance": 0,
"address": null,
"balance": 0,
"created": 1589322628,
"currency": "usd",
"default_source": "card_1Gi6cGHdG7kiS0bLynjuRExn",
"delinquent": false,
"description": null,
"discount": null,
"email": "test1111#gmail.com",
"id": "cus_HGduaDYZxYsNep",
"invoice_prefix": "2469C675",
"invoice_settings": {
"custom_fields": null,
"default_payment_method": null,
"footer": null
},
"livemode": false,
"metadata": {},
"name": null,
"next_invoice_sequence": 2,
"object": "customer",
"phone": null,
"preferred_locales": [],
"shipping": null,
"sources": {
"data": [
{
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_HGduaDYZxYsNep",
"cvc_check": "unchecked",
"dynamic_last4": null,
"exp_month": 5,
"exp_year": 2021,
"fingerprint": "fEOTy80zKG0YbTwA",
"funding": "credit",
"id": "card_1Gi6cGHdG7kiS0bLynjuRExn",
"last4": "5126",
"metadata": {},
"name": "test1111#gmail.com",
"object": "card",
"tokenization_method": null
}
],
"has_more": false,
"object": "list",
"total_count": 1,
"url": "/v1/customers/cus_HGduaDYZxYsNep/sources"
},
"subscriptions": {
"data": [
{
"application_fee_percent": null,
"billing": "charge_automatically",
"billing_cycle_anchor": 1589322628,
"billing_thresholds": null,
"cancel_at": null,
"cancel_at_period_end": false,
"canceled_at": null,
"collection_method": "charge_automatically",
"created": 1589322628,
"current_period_end": 1592001028,
"current_period_start": 1589322628,
"customer": "cus_HGduaDYZxYsNep",
"days_until_due": null,
"default_payment_method": null,
"default_source": null,
"default_tax_rates": [],
"discount": null,
"ended_at": null,
"id": "sub_HGducAJ2Ox9H35",
"invoice_customer_balance_settings": {
"consume_applied_balance_on_void": true
},
"items": {
"data": [
{
"billing_thresholds": null,
"created": 1589322628,
"id": "si_HGduoRX8OyZSOj",
"metadata": {},
"object": "subscription_item",
"plan": {
"active": true,
"aggregate_usage": null,
"amount": 1999,
"amount_decimal": "1999",
"billing_scheme": "per_unit",
"created": 1589253059,
"currency": "usd",
"id": "plan_HGLCsqbTMnWJJU",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"nickname": "Monthly",
"object": "plan",
"product": "prod_HGLAvChw1qUMHd",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": 7,
"usage_type": "licensed"
},
"price": {
"active": true,
"billing_scheme": "per_unit",
"created": 1589253059,
"currency": "usd",
"id": "plan_HGLCsqbTMnWJJU",
"livemode": false,
"lookup_key": null,
"metadata": {},
"nickname": "Monthly",
"object": "price",
"product": "prod_HGLAvChw1qUMHd",
"recurring": {
"aggregate_usage": null,
"interval": "month",
"interval_count": 1,
"trial_period_days": 7,
"usage_type": "licensed"
},
"tiers": null,
"tiers_mode": null,
"transform_quantity": null,
"type": "recurring",
"unit_amount": 1999,
"unit_amount_decimal": "1999"
},
"quantity": 1,
"subscription": "sub_HGducAJ2Ox9H35",
"tax_rates": []
}
],
"has_more": false,
"object": "list",
"total_count": 1,
"url": "/v1/subscription_items?subscription=sub_HGducAJ2Ox9H35"
},
"latest_invoice": "in_1Gi6cKHdG7kiS0bLVxWHYMMW",
"livemode": false,
"metadata": {},
"next_pending_invoice_item_invoice": null,
"object": "subscription",
"pause_collection": null,
"pending_invoice_item_interval": null,
"pending_setup_intent": null,
"pending_update": null,
"plan": {
"active": true,
"aggregate_usage": null,
"amount": 1999,
"amount_decimal": "1999",
"billing_scheme": "per_unit",
"created": 1589253059,
"currency": "usd",
"id": "plan_HGLCsqbTMnWJJU",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"nickname": "Monthly",
"object": "plan",
"product": "prod_HGLAvChw1qUMHd",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": 7,
"usage_type": "licensed"
},
"quantity": 1,
"schedule": null,
"start": 1589322628,
"start_date": 1589322628,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"has_more": false,
"object": "list",
"total_count": 1,
"url": "/v1/customers/cus_HGduaDYZxYsNep/subscriptions"
},
"tax_exempt": "none",
"tax_ids": {},
"tax_info": null,
"tax_info_verification": null
}
],
"has_more": true,
"object": "list",
"url": "/v1/customers"
}
current output
id object account_balance address balance created \
0 cus_HGduaDYZxYsNep customer 0 None 0 1589322628
currency default_source delinquent description discount \
0 usd card_1Gi6cGHdG7kiS0bLynjuRExn False None None
email invoice_prefix livemode name next_invoice_sequence \
0 test1111#gmail.com 2469C675 False None 2
phone preferred_locales shipping tax_exempt tax_info tax_info_verification \
0 None [] None none None None
invoice_settings.custom_fields invoice_settings.default_payment_method \
0 None None
invoice_settings.footer sources.object \
0 None list
sources.data sources.has_more \
0 [{'id': 'card_1Gi6cGHdG7kiS0bLynjuRExn', 'obje... False
sources.total_count sources.url \
0 1 /v1/customers/cus_HGduaDYZxYsNep/sources
subscriptions.object subscriptions.data \
0 list [{'id': 'sub_HGducAJ2Ox9H35', 'object': 'subsc...
subscriptions.has_more subscriptions.total_count \
0 False 1
subscriptions.url tax_ids.object tax_ids.data \
0 /v1/customers/cus_HGduaDYZxYsNep/subscriptions list []
tax_ids.has_more tax_ids.total_count \
0 False 0
tax_ids.url
0 /v1/customers/cus_HGduaDYZxYsNep/tax_ids
give jmespath a whirl; it can help with some intricate nested data.
Key takeaways : if it is a dict, u can access it with the . notation; if it is an array/list, u access it with the [] notation. it could be [*] or []. u can read the docs for more on that.
the first path is a dict(data), which leads to an array, which contains a dict... our end point is the subscriptions array :
dict-> array ->dict - >array
actual code :
import jmespath
expression = jmespath.compile('data[].subscriptions[]')
expression.search(content)
the subscriptions array is nested. so u need to know exactly what u want, and then adapt to it. if u know exactly how ur data should look, or still have issues, just post ur expected output, and where u got stuck, and someone should help out
The following got me into the nested array.
from pandas.io.json import json_normalize
stripe.api_key = "tes_api###############"
cus_data = stripe.Customer.list(limit=1)
cus_data = json_normalize(cus_data['data'],'subscriptions')
print(cus_data)
I am trying to parse JIRA webhook comment section properly. Now, following code works well for the first comment:
data = request.json
jira_comment = data['issue']['fields']['comment']['comments'][0].get('body')
However, every time new webhook is fired, for example, new comment is added, I can only receive the first comment in the JSON-message. If I could somehow identify each comment from another or only parse always the last comment of the issue. What would be the best way to do it or is it even possible since JIRA webhook JSON looks broken (multiple 'body' keys).
See JSON data below, to make it cleaner, use this http://jsbeautifier.org/:
{
"timestamp": 1443024903340,
"webhookEvent": "jira:issue_updated",
"user": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"issue": {
"id": "10300",
"self": "http://192.168.10.58:8080/rest/api/2/issue/10300",
"key": "DEMO-6",
"fields": {
"issuetype": {
"self": "http://192.168.10.58:8080/rest/api/2/issuetype/3",
"id": "3",
"description": "A task that needs to be done.",
"iconUrl": "http://192.168.10.58:8080/images/icons/issuetypes/task.png",
"name": "Task",
"subtask": false
},
"components": [],
"timespent": null,
"timeoriginalestimate": null,
"description": "Hey",
"project": {
"self": "http://192.168.10.58:8080/rest/api/2/project/10000",
"id": "10000",
"key": "DEMO",
"name": "DEMO",
"avatarUrls": {
"48x48": "http://192.168.10.58:8080/secure/projectavatar?avatarId=10011",
"24x24": "http://192.168.10.58:8080/secure/projectavatar?size=small&avatarId=10011",
"16x16": "http://192.168.10.58:8080/secure/projectavatar?size=xsmall&avatarId=10011",
"32x32": "http://192.168.10.58:8080/secure/projectavatar?size=medium&avatarId=10011"
}
},
"fixVersions": [],
"aggregatetimespent": null,
"resolution": null,
"timetracking": {},
"customfield_10006": null,
"attachment": [],
"customfield_10009": "0|i0000f:",
"aggregatetimeestimate": null,
"resolutiondate": null,
"workratio": -1,
"summary": "Comment test",
"lastViewed": "2015-09-23T19:14:11.979+0300",
"watches": {
"self": "http://192.168.10.58:8080/rest/api/2/issue/DEMO-6/watchers",
"watchCount": 1,
"isWatching": true
},
"creator": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"subtasks": [],
"created": "2015-09-21T17:39:14.518+0300",
"reporter": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"customfield_10000": null,
"aggregateprogress": {
"progress": 0,
"total": 0
},
"priority": {
"self": "http://192.168.10.58:8080/rest/api/2/priority/2",
"iconUrl": "http://192.168.10.58:8080/images/icons/priorities/high.png",
"name": "High",
"id": "2"
},
"customfield_10001": null,
"customfield_10100": "1234",
"customfield_10200": null,
"labels": [],
"customfield_10004": null,
"environment": null,
"timeestimate": null,
"aggregatetimeoriginalestimate": null,
"versions": [],
"duedate": null,
"progress": {
"progress": 0,
"total": 0
},
"comment": {
"startAt": 0,
"maxResults": 3,
"total": 3,
"comments": [{
"self": "http://192.168.10.58:8080/rest/api/2/issue/10300/comment/10600",
"id": "10600",
"author": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"body": "Comment 1",
"updateAuthor": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"created": "2015-09-23T19:05:26.593+0300",
"updated": "2015-09-23T19:08:07.010+0300"
}, {
"self": "http://192.168.10.58:8080/rest/api/2/issue/10300/comment/10601",
"id": "10601",
"author": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"body": "Comment 2",
"updateAuthor": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"created": "2015-09-23T19:08:13.644+0300",
"updated": "2015-09-23T19:08:13.644+0300"
}, {
"self": "http://192.168.10.58:8080/rest/api/2/issue/10300/comment/10606",
"id": "10606",
"author": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"body": "Comment 3",
"updateAuthor": {
"self": "http://192.168.10.58:8080/rest/api/2/user?username=jhdoe",
"name": "jhdoe",
"key": "jhdoe",
"emailAddress": "john.doe#corp.com",
"avatarUrls": {
"48x48": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=48",
"24x24": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=24",
"16x16": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=16",
"32x32": "http://www.gravatar.com/avatar/f94b6b6c15d155f4d4b3b2c05509ab0a?d=mm&s=32"
},
"displayName": "John Doe",
"active": true,
"timeZone": "Europe/Berlin"
},
"created": "2015-09-23T19:13:24.836+0300",
"updated": "2015-09-23T19:14:04.464+0300"
}]
},
"issuelinks": [],
"votes": {
"self": "http://192.168.10.58:8080/rest/api/2/issue/DEMO-6/votes",
"votes": 0,
"hasVoted": false
},
"worklog": {
"startAt": 0,
"maxResults": 20,
"total": 0,
"worklogs": []
},
"assignee": null,
"updated": "2015-09-23T19:15:03.338+0300",
"status": {
"self": "http://192.168.10.58:8080/rest/api/2/status/10000",
"description": "",
"iconUrl": "http://192.168.10.58:8080/images/icons/subtask.gif",
"name": "To Do",
"id": "10000",
"statusCategory": {
"self": "http://192.168.10.58:8080/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "To Do"
}
}
}
},
"changelog": {
"id": "10611",
"items": [{
"field": "Custom ID",
"fieldtype": "custom",
"from": null,
"fromString": null,
"to": null,
"toString": "1234"
}]
}
}
Well your comment section in the json is a list of dicts so you can always get the last in the list then call .get('body')
jira_comment = data['issue']['fields']['comment']['comments'][-1].get('body')
this works because in python negative numbers in an array index are treated as going backwards in the array. so -1 gives you the last item in the array.
Does your code work when there is no comments at all?
If it doesn't consider checking that the length of the the comments array is greater than 0 or just wrap it in a try except block.
When a comment is added, the request body should contain data['comment'], which will contain the comment that triggered the issue update. You can compare data['comment']['created'] and data['comment']['updated'] to figure if the comment is new or if the comment has been edited.
see https://developer.atlassian.com/jiradev/jira-apis/webhooks