0

I'm trying to create an endpoint that returns data in specific order when called.

Here is an example version that is working correctly:

example = {
  "responseVersion": "v3",
  "totalCount": 0,
  "sections": [
    {
      "id": "123",
      "title": "Invoice ID: 1234",
      "linkUrl": "http://example.com/1",
      "tokens": [
        {
          "label": "Valid",
          "dataType": "STRING",
          "value": "2019-08-04 - 2020-08-04",
          "name": "valid_date",
        },
        {
          "label": "STATUS",
          "dataType": "STATUS",
          "name": "status",
          "value": "Ended",
        }
      ],
    },
  ]
}

 @app.get("/")
 async def root():
  return example

Here is a simplified version of the code that I'm trying to get working:

def create_contract_cards(data):
  cards = []
  for i in data:
    card = {
      "id": i["ContractID"],
      "title": "Invoice ID: {}".format(i["ContractID"]),
      "linkUrl": "http://example.com/1",
      "tokens": [
        {
          "label": "Valid",
          "dataType": "STRING",
          "value": "2019-08-04 - 2020-08-04",
          "name": "valid_date",
        },
        {
          "label": "STATUS",
          "dataType": "STATUS",
          "name": "status",
          "value": "Ended",
        }
      ]
    }
    cards.append(card)

  example_data = {
  "responseVersion": "v3",
  "totalCount": len(cards),
  "sections": cards
  }
  return example_data

 @app.get("/")
 async def root():
  #data will be fetched here from another endpoint but i leave it out to keep things simple
  all_cards = create_contract_cards(data)
  pprint(all_cards) 
  return all_cards

At this point I'd expect everything working correctly, but the the data is actually is getting reordered which I thought shouldn't happen if using Python 3.7 or above.

As of Python version 3.7, dictionaries are ordered. In Python 3.6 and earlier, dictionaries are unordered.

Here is pretty printed output of that all_cards variable:

{'responseVersion': 'v3',
 'sections': [{'id': 'C000000010',
               'linkUrl': 'http://example.com/1',
               'title': 'Invoice ID: C000000010',
               'tokens': [{'dataType': 'STRING',
                           'label': 'Valid',
                           'name': 'valid_date',
                           'value': '2019-08-04 - 2020-08-04'},
                          {'dataType': 'STATUS',
                           'label': 'STATUS',
                           'name': 'status',
                           'value': 'Ended'}]}],
 'totalCount': 1}

As you can see its not in the same order when I created it.

I've also tried to use OrderedDict():

def create_contract_cards(data):
  cards = []
  for i in data:
    card = OrderedDict()
    card['id'] = i["ContractID"]
    card['title'] = i["ContractID"]
    card['linkUrl'] = "http://example.com/1"
    card['tokens'] = [
        {
          "label": "Valid",
          "dataType": "STRING",
          "value": "2019-08-04 - 2020-08-04",
          "name": "valid_date",
        },
        {
          "label": "STATUS",
          "dataType": "STATUS",
          "name": "status",
          "value": "Ended",
        }
      ]
    cards.append(card)

  example_data = {
  "responseVersion": "v3",
  "totalCount": len(cards),
  "sections": cards
  }
  return example_data

 @app.get("/")
 async def root():
  #data will be fetched here from another endpoint but i leave it out to keep things simple
  all_cards = create_contract_cards(data) 
  return all_cards

Does anyone has a idea why is this happening and why my code doesn't work like the first example?

All help is appreciated, thanks in advace!

The technologies used in the project:

  • Python version 3.10.5 (poetry)
  • FastAPI
ron_554
  • 13
  • 2
  • 2
    `"As you can see its not in the same order when I created it."` Actually we can't see. the source of `data` is excluded and you are telling us to assume it is in a particular ordering. – h0r53 Jun 28 '22 at 15:44
  • If I had to guess, the issue is likely with the jsonification, json is not ordered. This is discussed more here: https://stackoverflow.com/questions/3948206/json-order-mixed-up – Raymi306 Jun 28 '22 at 15:46
  • What exactly are you trying to order? In your first example your `totalCount` is 0 and `sections` is a list with a single entry. In the final example `totalCount` is 1 and `sections` is a list with a single entry. Lists retain ordering. What dictionary are you trying to order, the fields of the single `card` dictionary? – h0r53 Jun 28 '22 at 15:48
  • 2
    https://docs.python.org/3/library/pprint.html _"Dictionaries are sorted by key before the display is computed."_ – Anentropic Jun 28 '22 at 15:51

1 Answers1

7

The issue is not with the dictionary but with pprint. It sorts keys alphabetically by default. Use sort_dicts=False to avoid this:

pprint(all_cards, sort_dicts=False)

But in general, you should not rely on keys being ordered.

Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48