3

Python noob here. I'm trying to create a python script to auto-generate a JSON with multiple itemAvailability records (aka Objects) using a for loop to generate them, the JSON message is structured and cardinality are as follows:

messageHeader[1]
-itemId [1]
--itemAvailability [1-*]

The itemAvailability record lets the system know when the item is available and I'm trying to create a loop so that it will create random itemAvailability times for the next 28 days. I've tried looking online but cannot see anything that solves this particular problem, I have tested the functions and for loop in isolation so know they work but cannot get the for loop to create more than one itemAvailability record in a JSON. I can get a one to one conversion but as soon as I try any form of looping it blows up or does not create more than one itemAvailability record. I'm struggling to see anything online for being able to create JSON's using python with multiple objects of the same type, the code so far I have:

    import json
from datetime import datetime, timedelta
import math
from random import randrange


def starttimestamp(curr, delta):
    start = datetime.min + math.ceil((curr - datetime.min) / delta) * delta
    formatted = start.strftime("%Y-%m-%dT%H:%M:%SZ")
    return formatted


def endtimestamp(curr, delta):
    end = datetime.min + math.ceil((curr - datetime.min) / delta) * delta + timedelta(minutes=randrange (30,600,30))
    formatted = end.strftime("%Y-%m-%dT%H:%M:%SZ")
    return formatted


timestamp = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")

data = {'messageId': "theId", 'transId': 'theOtherId',
        'createdTimestamp': timestamp, 'itemList': [{
            'itemId': "I"}]}

today = datetime.now()
next_day = timedelta(days = 1)

date_counter = 0
for days in range(0, 28):
    date_counter += 1
    today += next_day
    curr = today
    data['itemList'][0]['itemAvailability'] = {
    'startTimestamp': starttimestamp(curr, timedelta(minutes=30)),
    'endTimestamp' : endtimestamp(curr, timedelta(minutes=30))}

with open(r'C:\\Somewhere.json', 'w') as outfile:
json.dump(data, outfile)

What I get is this:

{
"messageId": "theId",
"transId": "theOtherId",
"createdTimestamp": "2019-04-08T00:32:47Z",
"itemList": [{
    "itemId": "I",
    "itemAvailability": {
        "startTimestamp": "2019-05-06T01:00:00Z",
        "endTimestamp": "2019-05-06T06:30:00Z",
        "availability": "A"
    }
}]

}

But what I want is something like this:

{
"messageId": "theId",
"transId": "theOtherId",
"createdTimestamp": "2019-04-08T00:32:47Z",
"itemList": [{
        "itemId": "I",
        "itemAvailability": {
            "startTimestamp": "2019-05-06T01:00:00Z",
            "endTimestamp": "2019-05-06T06:30:00Z",
            "availability": "A",
            "itemAvailability": {
                "startTimestamp": "2019-05-06T01:00:00Z",
                "endTimestamp": "2019-05-06T06:30:00Z",
                "availability": "A",
                "itemAvailability": {
                    "startTimestamp": "2019-05-06T01:00:00Z",
                    "endTimestamp": "2019-05-06T06:30:00Z",
                    "availability": "A",
                    "itemAvailability": {
                        "startTimestamp": "2019-05-06T01:00:00Z",
                        "endTimestamp": "2019-05-06T06:30:00Z",
                        "availability": "A",
                        "itemAvailability": {
                            "startTimestamp": "2019-05-06T01:00:00Z",
                            "endTimestamp": "2019-05-06T06:30:00Z",
                            "availability": "A",
                            "itemAvailability": {
                                "startTimestamp": "2019-05-06T01:00:00Z",
                                "endTimestamp": "2019-05-06T06:30:00Z",
                                "availability": "A"
                            }
                        }
                        ]
                    }
5
  • Im confused on what you expect to get vs what you actually get. Can you reword your question? Commented Apr 8, 2019 at 0:40
  • Thanks and sorry I have now reworded and explained it better Commented Apr 8, 2019 at 8:47
  • I've edit the main text to add a bit more clarity as I wrote it in the early hours of the morning Commented Apr 8, 2019 at 10:50
  • Are you sure you want it nested each time? Or do you just want it to be a list? Commented Apr 8, 2019 at 12:21
  • Cheers, It should be nested but my mock up JSON not quite right Commented Apr 8, 2019 at 12:35

1 Answer 1

1

A json object is just a dictionary or hash table. This means that EVERY key must be unique.

For Example:

d[1] = 'a' # d = {1: 'a'}
d[1] = 'b' # d = {1: 'b'} - Note that the value for 1 is overridden.

So from your code:

for days in range(0, 28):
    date_counter += 1
    today += next_day
    curr = today

    # Note the key for your `data` dictionary never changes.
    # Your code is always writing to the same key: ['itemList'][0]['itemAvailability'].
    data['itemList'][0]['itemAvailability'] = {
    'startTimestamp': starttimestamp(curr, timedelta(minutes=30)),
    'endTimestamp' : endtimestamp(curr, timedelta(minutes=30))}

To solve this, and meet your desired output

import json
from datetime import datetime, timedelta
import math
from random import randrange


def starttimestamp(curr, delta):
    start = datetime.min + math.ceil((curr - datetime.min) / delta) * delta
    formatted = start.strftime("%Y-%m-%dT%H:%M:%SZ")
    return formatted


def endtimestamp(curr, delta):
    end = datetime.min + math.ceil((curr - datetime.min) / delta) * delta + timedelta(minutes=randrange (30,600,30))
    formatted = end.strftime("%Y-%m-%dT%H:%M:%SZ")
    return formatted


timestamp = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")

data = {'messageId': "theId", 'transId': 'theOtherId',
        'createdTimestamp': timestamp, 'itemList': [{
            'itemId': "I"}]}

today = datetime.now()
next_day = timedelta(days = 1)

date_counter = 0

# We need the ability to move a pointer down the dictionary.
temp_data = data['itemList'][0]

for days in range(0, 28):
    date_counter += 1
    today += next_day
    curr = today
    temp_data['itemAvailability'] = { # Create the dict for our current level
    'startTimestamp': starttimestamp(curr, timedelta(minutes=30)),
    'endTimestamp' : endtimestamp(curr, timedelta(minutes=30)),
    'availability': 'A',
    'itemAvailability': dict()
    }
    temp_data = temp_data['itemAvailability'] # Move the pointer down one level

print(json.dumps(data, indent=4))

Note: I do not recommend nesting your payload this way. If every object is the same then you shouldn't nest it but instead list it.

date_counter = 0

data['itemList'][0]['itemAvailability'] = list()

for days in range(0, 28):
    date_counter += 1
    today += next_day
    curr = today
    data['itemList'][0]['itemAvailability'].append({
    'startTimestamp': starttimestamp(curr, timedelta(minutes=30)),
    'endTimestamp' : endtimestamp(curr, timedelta(minutes=30)),
    'availability': 'A',
    })

print(json.dumps(data, indent=4))
Sign up to request clarification or add additional context in comments.

2 Comments

Great, awesome, this has done the trick and thanks for your help and explaining everything so clearly and for the tip re the payload. I'll use that going forward and incorporate it into my other scripts :)
I have a new question I have asked related to this but posted as a new question as I thought it deserved the kudos for asking, it's here if you have any appetite to review, stackoverflow.com/questions/55681612/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.