As of mypy 0.990, mypy finally supports recursive type annotations, using the natural syntax:

from typing import Union, Dict, List

JSONVal = Union[None, bool, str, float, int, List['JSONVal'], Dict[str, 'JSONVal']]

d: JSONVal = {'a': ['b']}

mypy output:

Success: no issues found in 1 source file

Before 0.990, this would produce an error reporting a lack of recursive type support:

$ mypy asdf.py
asdf.py:3: error: Recursive types not fully supported yet, nested types replaced with "Any"

On such versions, Dict[str, Any] would be the way to go.


You can also use mutually recursive type aliases now, so you can do things like

from typing import Union, Dict, List

JSONVal = Union[None, bool, str, float, int, 'JSONArray', 'JSONObject']
JSONArray = List[JSONVal]
JSONObject = Dict[str, JSONVal]

d: JSONObject = {'a': ['b']}
Answer from user2357112 on Stack Overflow
🌐
PyPI
pypi.org › project › python-easy-json
python-easy-json · PyPI
python-easy-json is a recursive JSON to python object deserializer with support for defining data models and casting data to python using type hint annotations.
      » pip install python-easy-json
    
Published: Jan 17, 2026
Version: 1.2.4
Discussions

json - using recursive function and structure type in python? - Stack Overflow
I have one json file which i want to iterate using recursive function , but how to check whether my json structure is string , array , list or object ? If its array and inside array there are 5 ob... More on stackoverflow.com
🌐 stackoverflow.com
September 27, 2018
recursion - Recursive search in json with python - Stack Overflow
instead of check on the timestamp it is possible to do that considering if the "type" is "Recursive" ? since sometimes timestamp is present even in type nothing....but for semplicity I removed it in the json example 2021-07-28T14:37:02.583Z+00:00 More on stackoverflow.com
🌐 stackoverflow.com
python - After recursive search of my json object how to determine data type for looping data - Stack Overflow
I have a recursive function that examines a json object. It captures the data when I try to loop the data, it works for one but not the other. I need help determining what type of data the returne... More on stackoverflow.com
🌐 stackoverflow.com
Json Type in Mypy.
json() returns JSON parsed as Python dictionaries and lists, so list | dict would work. That's pretty broad though, and may lead to issues down the road when reading this data, since lists and dicts have quite different interfaces. If you know exactly what shape of data is returned (which is usually the case), you would specify that instead. If it's a list of strings returned, you'd do list[str], for example. If it's a dictionary with specific keys though, look into a TypedDict. It allows you to specify the expected keys and the types of the associated values. More on reddit.com
🌐 r/learnpython
13
1
January 16, 2025
🌐
Python.org
discuss.python.org › ideas
Generic `typing.ForwardRef` to support generic recursive types - Ideas - Discussions on Python.org
October 21, 2022 - E.g.: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] Recursive types need to use ForwardRefs at the right-hand side to reference the type alias before assignment.
Top answer
1 of 3
1

with recursion you can do something like this:

result = []

def finditem(obj, key):
    if key in obj: result.append({"timestamp": obj[key], "text": obj['textsList'][0]['text']})
    for k, v in obj.items():
        if isinstance(v,dict):
            item = finditem(v, key)
            if item is not None:
                result.append({"timestamp": item,"text":v['textsList'][0]['text']})
        elif isinstance(v,list):
            for i in v:
                item = finditem(i, key)
                if item is not None:
                    result.append({"timestamp": item,"text": i['textsList'][0]['text']})

finditem(data, 'timestamp')
print (result)

result:

[{'timestamp': 1234567890, 'text': 'some text here 0'}, {'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]

EDIT:

result = []
def finditem(obj, key):
    if key in obj and obj[key]=='Recursive': result.append({"timestamp": obj["data"]["timestamp"],"text": obj["data"]['textsList'][0]['text']})
    for k, v in obj.items():
        if isinstance(v,dict):
            item = finditem(v, key)
            if item == 'Recursive':
                d = v['timestamp']
                result.append({"timestamp": d,"text": v['textsList'][0]['text']})
        elif isinstance(v,list):
            for list_item in v:
                item = finditem(list_item, key)
                if item == 'Recursive':
                    d = list_item['timestamp']
                    result.append({"timestamp": d,"text": list_item['textsList'][0]['text']})

finditem(data,'type')
print (result)

result:

[{'timestamp': 12345678901234, 'text': 'some other text 1'}, {'timestamp': 12345678901234, 'text': 'some other text 2'}]
2 of 3
1

You can use a recursive generator function:

def get_text(d):
   if isinstance(d, dict):
      if 'timestamp' in d:
         yield {'timestamp':d['timestamp'], 'textsList':''.join(i['text'] for i in d['textsList'])}
      for b in d.values():
         yield from get_text(b)
   elif isinstance(d, list):
      yield from [i for j in d for i in get_text(j)]

data = {'result': [{'timestamp': 1234567890, 'textsList': [{'text': 'some text here 0'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 1'}], 'otherList': [{'type': 'Nothing'}, {'type': 'Recursive', 'data': {'timestamp': 12345678901234, 'textsList': [{'text': 'some other text 2'}], 'otherList': []}}]}}]}]}
print(list(get_text(data)))

Output:

[{'timestamp': 1234567890, 'textsList': 'some text here 0'}, 
 {'timestamp': 12345678901234, 'textsList': 'some other text 1'}, 
 {'timestamp': 12345678901234, 'textsList': 'some other text 2'}]
🌐
Stack Overflow
stackoverflow.com › questions › 75697579 › after-recursive-search-of-my-json-object-how-to-determine-data-type-for-looping
python - After recursive search of my json object how to determine data type for looping data - Stack Overflow
targetType = 'equal' def find_data(lookup_key, jsonData, search_result = []): if type(jsonData) == dict: for key, value in jsonData.items(): if targetType == 'equal' and key == lookup_key: search_result.append(value) elif targetType == 'regex' and pattern.search(key): search_result.append(value) find_data(lookup_key, value, search_result) elif type(jsonData) == list: for element in jsonData: find_data(lookup_key, element, search_result) return search_result
🌐
Reddit
reddit.com › r/learnpython › json type in mypy.
r/learnpython on Reddit: Json Type in Mypy.
January 16, 2025 -

Hey there! I have a weird question but Im stuck for days on this.

I have quite a lot of requests done via python using the requests module.

def url_requester(url: str) -> list | ???: response=requests.request(method, payload, url, etc) if method=="get": return response.json()[0] return response.json()

Is there a proper way you type hint this function? It has being killing me, mypy says it is wrong . Thanks!

Top answer
1 of 3
3
json() returns JSON parsed as Python dictionaries and lists, so list | dict would work. That's pretty broad though, and may lead to issues down the road when reading this data, since lists and dicts have quite different interfaces. If you know exactly what shape of data is returned (which is usually the case), you would specify that instead. If it's a list of strings returned, you'd do list[str], for example. If it's a dictionary with specific keys though, look into a TypedDict. It allows you to specify the expected keys and the types of the associated values.
2 of 3
3
I vaguely recall someone telling me MyPy can now cope with recursive types. Playing with this on MyPy's playground, you can rig something together that can in theory represent JSON in a type-safe way (although not with the ability to assert things like "this array must always hold strings"). import json from collections.abc import Mapping, Sequence from typing import AnyStr, cast type JsonNull = None type JsonBool = bool type JsonNumber = int | float type JsonString = str type JsonArray = Sequence[JsonType] type JsonObject = Mapping[JsonString, JsonType] type JsonContainer = JsonArray | JsonObject type JsonType = JsonNull | JsonBool | JsonNumber | JsonString | JsonContainer def json_loads(raw: AnyStr) -> JsonContainer: return cast(JsonContainer, json.loads(raw)) This will at least force you to validate that types are specific JSON-compatible values prior to doing things with it. I may have forgotten some edge cases, and yes, this is overengineered IMHO. Generally if you care about types to this extent, you'd be better off using something like Pydantic and converting your requests responses to a proper typed object before returning it where possible.
Find elsewhere
🌐
Medium
medium.com › @marcnealer › python-recursive-functions-extracting-data-from-javascript-json-blobs-bc11738f1228
Python Recursive Functions: Extracting data from JavaScript/JSON blobs | by Marc Nealer | Medium
August 25, 2024 - This example is not one I think you should use. There are way better ways of doing this, but it shows how recursive functions work and they can replace loops. You can see from the sequence diagram this is a straight recursive call. You should note that python has a 10,000 recursive depth limit set.
🌐
Medium
medium.com › @n0mn0m › recursive-search-with-python-ceab8c8d1eb3
Recursive Search with Python. Recently I received from JSON like data… | by Alexander Hagerman | Medium
October 31, 2021 - Luckily Python has acopy module in the standard library to help with this scenario. The function below represents my final result. This worked well on the sample data, and eventually was used on PySpark RDDs to process hundreds of millions of structures quickly. import copy from future.utils import iteritems def search ( input , row_base , search_key , results ): """ A search function to help transform nested JSON like objects into tabular rows.
🌐
GitHub
github.com › python › mypy › issues › 13693
Recursive Generic Type Support · Issue #13693 · python/mypy
September 20, 2022 - Bug Report In: #731 #13297 (not released yet in v0.971) We now support recursive type hints, such as: JSON = Union[Dict[str, 'JSON'], List['JSON'], str, int, float, bool, None] But ...
Author: python
🌐
Reddit
reddit.com › r/learnpython › converting json into dictionary and recursion
r/learnpython on Reddit: converting JSON into dictionary and recursion
November 13, 2022 -

I am studying trying to self teach python with an online course and I am stuck on a question I would like some help with, the question is:

"George runs a company. He manages James and Jamila, who each have a small team to manage. In James' team are Jill and Jenny. In Jamila's team are Jewel, Jasmine and Jeremy. Create a JSON object in a string variable called company where each item has a name field and a field called manages which contains an array of the people managed by that person. If a person does not manage anybody, they have no field called manages. Then convert the JSON string to a dictionary in a variable called company_dict.

Finally, write a recursive function that accepts the dictionary as an argument and lists each person and their level in the organisation, so that George is at level 1, James and Jamila are at 2, and so on. Call the function and print the result. It should look like this: George is at level 1 James is at level 2 Jill is at level 3 Jenny is at level 3 Jamila is at level 2 Jewel is at level 3 Jasmine is at level 3 Jeremey is at level 3 The function can either return a string, which you print after it has been called, or it can print its results as it runs and return nothing."

Top answer
1 of 2
2

It's a little hard to understand exactly what you are after here, but it seems like for some reason you have a bunch of nested json and you want to search it for an id and return a list that represents the path down the json nesting. If so, the quick and easy path is to recurse on the dictionary (that you got from json.load) and collect the keys as you go. When you find an 'id' key that matches the id you are searching for you are done. Here is some code that does that:

def all_keys(search_dict, key_id):
    def _all_keys(search_dict, key_id, keys=None):
        if not keys:
            keys = []
        for i in search_dict:
            if search_dict[i] == key_id:
                return keys + [i]
            if isinstance(search_dict[i], dict):
                potential_keys = _all_keys(search_dict[i], key_id, keys + [i])
                if 'id' in potential_keys:
                    keys = potential_keys
                    break
        return keys
    return _all_keys(search_dict, key_id)[:-1]

The reason for the nested function is to strip off the 'id' key that would otherwise be on the end of the list.

This is really just to give you an idea of what a solution might look like. Beware the python recursion limit!

2 of 2
0

Based on the assumption that you need the full dictionary path until a key named id has a particular value, here's a recursive solution that iterates the whole dict. Bear in mind that:

  • The code is not optimized at all
  • For huge json objects it might yield StackOverflow :)
  • It will stop at first encountered value found (in theory there shouldn't be more than 1 if the json is semantically correct)

The code:

import json
from types import DictType

SEARCH_KEY_NAME = "id"
FOUND_FLAG = ()
CRONO_FILE = "a.jsn"


def decode_crono(crono_file):
    with open(crono_file) as json_file:
        return json.load(json_file)


def traverse_dict(dict_obj, value):
    for key in dict_obj:
        key_obj = dict_obj[key]
        if key == SEARCH_KEY_NAME and key_obj == value:
            return FOUND_FLAG
        elif isinstance(key_obj, DictType):
            inner = traverse_dict(key_obj, value)
            if inner is not None:
                return (key,) + inner
    return None


if __name__ == "__main__":
    value = "23314"
    json_dict = decode_crono(CRONO_FILE)
    result = traverse_dict(json_dict, value)
    print result
🌐
Hacker News
news.ycombinator.com › item
Last I checked, mypy struggled to represent recursive types. Think `JSON = Union... | Hacker News
May 11, 2021 - Worse, importing third party packages often fails silently and when you can get error messages they tend to be completely inactionable (I recall one error message which linked to a web page that had lots of details and workarounds for fixing other problems, but none of which solved the error itself)
🌐
Stack Overflow
stackoverflow.com › questions › 52536958 › using-recursion-in-json
python - using recursion in json - Stack Overflow
data = [] with open('Desktop/kaggle/records.json') as f: for line in f: data.append(json.loads(line)) data · I want to access NAME, class specially but want to iterate through all the elements and make dataframe for each attribute in separate column like _id, Istid, NAME, class, ackid, app, cusid. Please help me out with recursive function in Python!
🌐
Python
docs.python.org › 3 › library › json.html
JSON encoder and decoder — Python 3.14.8 documentation
If check_circular is true (the default), then lists, dicts, and custom encoded objects will be checked for circular references during encoding to prevent an infinite recursion (which would cause a RecursionError). Otherwise, no such check takes place. If allow_nan is true (the default), then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders.
🌐
Chopin's blog
chopin.hashnode.dev › validating-recursive-jsons-using-json-schema-in-python
Validating recursive JSONs using JSON Schema in Python
July 30, 2024 - JSON Schema seems to be an industry standard for this sort of stuff and they have a Python package jsonschema! JSON Schema facilitates many things, one of which is validation. >>> from jsonschema import validate >>> # A sample schema, like what we'd get from json.load() >>> schema = { ... "type" : "object", ...