Can Google Calendar extended properties be lists? - python

I want to add a set of extendedProperties to a Google Calendar event. I want some of those properties be lists. As (in python),
event = {
..., # standard properties
"extendedProperties": {
"shared": {
"max_crew": 3,
"crew_list": [
"crew1#example.com",
"crew2#example.com",
],
}
}
...
}
This creates the max_crew property but not the crew_list property.
Any way to do this? Or do I need to use a parse-able string (max 1024 chars)?

There is a way: explained in Google Calendar's guide and reference.
And in Python first create a dictionary for your extra fields.
body = {
"extendedProperties": {
"private": {
"petsAllowed": "yes"
}
}
}
Then make a request with:
service.events().patch(calendarId='calendar_id', eventId='event_id', body=body).execute()
If it is successful, it will return the updated event.

Hybor confirms my observation that the interface does not support a list as a value. Shortsighted, imho, but so it goes.

Related

Navigate dict based on its structure

I have a python code that interacts with multiple APIs. All of the APIs return some json but each has different structure. Let's say I'm looking for people's names in all these jsons:
json_a = {
"people": [
{"name": "John"},
{"name": "Peter"}
]
}
json_b = {
"humans": {
"names": ["Adam", "Martin"]
}
}
As you can see above the dictionaries from jsons have arbitrary structures. I'd like to define something that will serve as a "blueprint" for navigating each json, something like this:
all_jsons = {
"json_a": {
"url": "http://endpoint",
"json_structure": "people -> list -> name"
},
"json_b": {
"url": "http://someotherendpoint",
"json_structure": "humans -> names -> list"
}
}
So that if I'm working with json_a I'll just look into all_jsons["json_a"]["json_structure"] and I have an information on how to navigate this exact json. What would be the best way to achieve this?
Why not define concrete retrieval functions for each api:
def retrieve_a(data):
return [d["name"] for d in data["people"]]
def retrieve_b(data):
return data["humans"]["names"]
and store them for each endpoint:
all_jsons = {
"json_a": {
"url": "http://endpoint",
"retrieve": retrieve_a
},
"json_b": {
"url": "http://someotherendpoint",
"retrieve": retrieve_b
}
}
I have found this approach more workable than trying to express code-logic by configuration. Then you can easily collect names:
for dct in all_jsons.values():
data = ... # requests.get(dct["url"]).json() # or similar
names = dct["retrieve"](data)
To get a value from a dictionary with a key if it may not exist, dict.get(key) is used for. To distinguish which type list or dict or else, type(val) is useful for. Combination of them should achieve your problem.

Django: Transform dict of queryset

I use the following code to get my data out of the dict.
test = self.events_max_total_gross()
events = organizer.events.all()
for event in events:
test.get(event.pk, {}).values()
[...]
I use this query set to get the data. My question is: Does the transformation at the end makes sense or is there a better way to access the dict (without transforming it first). As I have several of these my approach doesn't seem to follow the DRY principle.
def events_max_total_gross(self):
events_max_total_gross = (
Event.objects.filter(
organizer__in=self.organizers,
status=EventStatus.LIVE
)
.annotate(total_gross=Sum(F('tickets__quantity') * F('tickets__price_gross')))
.values('pk', 'total_gross')
)
"""
Convert this
[
{
'pk': 2,
'total_gross': 12345
},
{
'pk': 3,
'total_gross': 54321
},
...
]
to this:
{
2: {
'total_gross': 12345,
},
3: {
'total_gross': 12345,
}
...
}
"""
events_max_total_gross_transformed = {}
for item in events_max_total_gross:
events_max_total_gross_transformed.setdefault(
item['pk'], {}
).update({'total_gross': item['total_gross']})
return events_max_total_gross_transformed
Use:
transformed = {
v['pk']: { 'total_gross': v['total_gross'] } for v in events_max_total_gross
}
This is called a python dict comprehension. Google that term if you want tutorials or examples.
If I understood it correctly, then for every organiser's event you need total_gross, you can query like this instead of going over events and events_max_total_gross in loop.
First get all the events of that particular organizer.
event_ids = Event.objects.filter(organizer=organizer).values_list('id',flat=True)
Run this then:
Event.objects.filter(
id__in=event_ids,
organizer__in=self.organizers,
status=EventStatus.LIVE
)
.annotate(total_gross=Sum(F('tickets__quantity') * F('tickets__price_gross')))
.values('pk', 'total_gross')
)
This way you will save your transformation of dict and looping it over again.
In case you need to do like this because of some other requirement then you can use python dict comprehension:
events_max_total_gross_transformed = {
event['pk']: { 'total_gross': event['total_gross'] } for event in events_max_total_gross
}
But as you have several of these, you might wanna have a look at proxy-models also which might help. Here you can write manager functions to help you with your queries.

Podio: How do I use the Item.update-method in Python 3?

There is no example code for the Podio API for Python but this is the example code written for Ruby:
Podio::Item.update(210606, {
:fields => {
'title' => 'The API documentation is much more funny',
'business_value' => { :value => 20000, :currency => 'EUR' },
'due_date' => { :start => '2011-05-06 11:27:20', :end =>
5.days.from_now.to_s(:db) }
}
})
I can't for the life of me figure out how to translate this to Python 3. I've tried using dictionaries, dicts inside lists, referencing the field with both their field-id and their names etc. But it never actually updates anything.
This is my failed attempt at translating the above to Python code (with different fields since the fields in my 'Bugs (API example) app' aren't the same as in the example code):
newValues = {'fields':{'title': "This is my title",'description_of_problem':
"the not work"}}
try:
podio.Item.update(629783395, newValues['fields'])
print('updating was successful')
except:
print('updating was not successful')
With podio being:
podio = api.OAuthClient(
client_id,
client_secret,
username,
password,
)
The 'fields' part in my code doesn't make any sense really, but I couldn't figure out what else to do with that part of the Ruby code, I suspect that is the issue. The program always prints 'updating was successful' as if the Item.update method was successfully called, but as I said it doesn't actually update anything in Podio. Can anyone see what's wrong?
I'd just follow the Item update API, and pass in a dictionary that matches the request section there:
{
"revision": The revision of the item that is being updated. This is optional,
"external_id": The new external_id of the item,
"fields": The values for each field, see the create item operation for details,
"file_ids": The list of attachments,
"tags": The list of tags,
"reminder": Optional reminder on this task
{
"remind_delta": Minutes (integer) to remind before the due date
},
"recurrence": The recurrence for the task, if any,
{
"name": The name of the recurrence, "weekly", "monthly" or "yearly",
"config": The configuration for the recurrence, depends on the type
{
"days": List of weekdays ("monday", "tuesday", etc) (for "weekly"),
"repeat_on": When to repeat, "day_of_week" or "day_of_month" (for "monthly")
},
"step": The step size, 1 or more,
"until": The latest date the recurrence should take place
},
"linked_account_id": The linked account to use for meetings,
"ref" The reference of the item
{
"type": The type of reference,
"id": The id of the reference
}
}
The documentation further points to the item creation API for further examples. Note how that object has a "fields" key in the outermost mapping.
All the Ruby documentation does is build that mapping as a Ruby hash (in Python, a dict) with the entries that need updating; :field is an immutable string (called a symbol) that defines a key in that hash pointing to a nested hash. The Python implementation for the update method just converts that dictionary to a JSON post body.
A direct translation of the Ruby code to Python is:
from datetime import datetime, timedelta
podio.item.update(210606, {
'fields': {
'title': 'The API documentation is much more funny',
'business_value': {'value': 20000, 'currency': 'EUR'},
'due_date': {
'start': '2011-05-06 11:27:20',
'end': (datetime.now() + timedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')}
}
})
What you did wrong in your case is not include the 'fields' key in the outermost dictionary; you unwrapped the outermost dictionary and only posted the nested dictionary under 'fields'. Instead, include that outer dictionary:
newValues = {
'fields': {
'title': "This is my title",
'description_of_problem': "the not work"
}
}
podio.Item.update(629783395, newValues)

Error while parsing json from IBM watson using python

I am trying to parse out a JSON download using python and here is the download that I have:
{
"document_tone":{
"tone_categories":[
{
"tones":[
{
"score":0.044115,
"tone_id":"anger",
"tone_name":"Anger"
},
{
"score":0.005631,
"tone_id":"disgust",
"tone_name":"Disgust"
},
{
"score":0.013157,
"tone_id":"fear",
"tone_name":"Fear"
},
{
"score":1.0,
"tone_id":"joy",
"tone_name":"Joy"
},
{
"score":0.058781,
"tone_id":"sadness",
"tone_name":"Sadness"
}
],
"category_id":"emotion_tone",
"category_name":"Emotion Tone"
},
{
"tones":[
{
"score":0.0,
"tone_id":"analytical",
"tone_name":"Analytical"
},
{
"score":0.0,
"tone_id":"confident",
"tone_name":"Confident"
},
{
"score":0.0,
"tone_id":"tentative",
"tone_name":"Tentative"
}
],
"category_id":"language_tone",
"category_name":"Language Tone"
},
{
"tones":[
{
"score":0.0,
"tone_id":"openness_big5",
"tone_name":"Openness"
},
{
"score":0.571,
"tone_id":"conscientiousness_big5",
"tone_name":"Conscientiousness"
},
{
"score":0.936,
"tone_id":"extraversion_big5",
"tone_name":"Extraversion"
},
{
"score":0.978,
"tone_id":"agreeableness_big5",
"tone_name":"Agreeableness"
},
{
"score":0.975,
"tone_id":"emotional_range_big5",
"tone_name":"Emotional Range"
}
],
"category_id":"social_tone",
"category_name":"Social Tone"
}
]
}
}
I am trying to parse out 'tone_name' and 'score' from the above file and I am using following code:
import urllib
import json
url = urllib.urlopen('https://watson-api-explorer.mybluemix.net/tone-analyzer/api/v3/tone?version=2016-05-19&text=I%20am%20happy')
data = json.load(url)
for item in data['document_tone']:
print item["tone_name"]
I keep running into error that tone_name not defined.
As jonrsharpe said in a comment:
data['document_tone'] is a dictionary, but 'tone_name' is a key in dictionaries much further down the structure.
You need to access the dictionary that tone_name is in. If I am understanding the JSON correctly, tone_name is a key within tones, within tone_categories, within document_tone. You would then want to change your code to go to that level, like so:
for item in data['document_tone']['tone_categories']:
# item is an anonymous dictionary
for thing in item[tones]:
print(thing['tone_name'])
The reason more than one for is needed is because of the mix of lists and dictionaries in the file. 'tone_categories is a list of dictionaries, so it accesses each one of those. Then, it iterates through the list tones, which is in each one and full of more dictionaries. Those dictionaries are the ones that contain 'tone_name', so it prints the value of 'tone_name'.
If this does not work, let me know. I was unable to test it since I could not get the rest of the code to work on my computer.
You are incorrectly walking the structure. The root node has a single document_tone key, the value of which only has the tone_categories key. Each of the categories has a list of tones and it's name. Here is how you would print it out (adjust as needed):
for cat in data['document_tone']['tone_categories']:
print('Category:', cat['category_name'])
for tone in cat['tones']:
print('-', tone['tone_name'])
The result of this is:
Category: Emotion Tone
- Anger
- Disgust
- Fear
- Joy
- Sadness
Category: Language Tone
- Analytical
- Confident
- Tentative
Category: Social Tone
- Openness
- Conscientiousness
- Extraversion
- Agreeableness
- Emotional Range

Modify JSON response of Flask-Restless

I am trying to use Flask-Restless with Ember.js which isn't going so great. It's the GET responses that are tripping me up. For instance, when I do a GET request on /api/people for example Ember.js expects:
{
people: [
{ id: 1, name: "Yehuda Katz" }
]
}
But Flask-Restless responds with:
{
"total_pages": 1,
"objects": [
{ "id": 1, "name": "Yahuda Katz" }
],
"num_results": 1,
"page": 1
}
How do I change Flask-Restless's response to conform to what Ember.js would like? I have this feeling it might be in a postprocessor function, but I'm not sure how to implement it.
Flask extensions have pretty readable source code. You can make a GET_MANY postprocessor:
def pagination_remover(results):
return {'people': results['objects']} if 'page' in results else results
manager.create_api(
...,
postprocessors={
'GET_MANY': [pagination_remover]
}
)
I haven't tested it, but it should work.
The accepted answer was correct at the time. However the post and preprocessors work in Flask-Restless have changed. According to the documentation:
The preprocessors and postprocessors for each type of request accept
different arguments, but none of them has a return value (more
specifically, any returned value is ignored). Preprocessors and
postprocessors modify their arguments in-place.
So now in my postprocessor I just delete any keys that I do not want. For example:
def api_post_get_many(result=None, **kw):
for key in result.keys():
if key != 'objects':
del result[key]

Categories