{"id":46286056,"url":"https://github.com/nfergu/referrers","last_synced_at":"2026-03-04T07:02:37.115Z","repository":{"id":228683919,"uuid":"772587124","full_name":"nfergu/referrers","owner":"nfergu","description":"Referrers helps to answer the question \"what is holding a reference to this object?\", which is useful for debugging Python memory leaks and other issues.","archived":false,"fork":false,"pushed_at":"2025-11-24T22:38:55.000Z","size":465,"stargazers_count":8,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-16T21:15:56.217Z","etag":null,"topics":["memory","memory-leak","memory-leak-detection","python","python3","references","referrers"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nfergu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-03-15T13:44:02.000Z","updated_at":"2025-11-24T22:38:22.000Z","dependencies_parsed_at":"2024-04-08T22:31:23.593Z","dependency_job_id":"d6788537-8ea1-48f5-b17e-675f3e856940","html_url":"https://github.com/nfergu/referrers","commit_stats":null,"previous_names":["nfergu/referrers"],"tags_count":47,"template":false,"template_full_name":null,"purl":"pkg:github/nfergu/referrers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfergu%2Freferrers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfergu%2Freferrers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfergu%2Freferrers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfergu%2Freferrers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nfergu","download_url":"https://codeload.github.com/nfergu/referrers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nfergu%2Freferrers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30075425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T05:31:57.858Z","status":"ssl_error","status_checked_at":"2026-03-04T05:31:38.462Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["memory","memory-leak","memory-leak-detection","python","python3","references","referrers"],"created_at":"2026-03-04T07:02:36.545Z","updated_at":"2026-03-04T07:02:37.103Z","avatar_url":"https://github.com/nfergu.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Referrers\n\n![PyPI - Downloads](https://img.shields.io/pypi/dm/referrers)\n\nReferrers is a Python package that helps to answer the question **\"what is holding\na reference to this object?\"**, which is useful for debugging memory leaks and other\nissues. It tries to assign a meaningful name to each reference to an object and\nreturns a graph of referrers (including indirect referrers).\n\nFor example, this code:\n\n```python\nimport referrers\n\ndef my_function():\n    a = [2, 4]\n    d = dict(a=a)\n    print(referrers.get_referrer_graph(a))\n\nmy_function()\n```\n\nWill produce output like:\n\n```plaintext\n╙── list (object) (id=4343582848) (target)\n    ├── my_function.a (local) (id=4343582848) (root)\n    └── dict key=a (id=4345092160)\n        └── dict (object) (id=4345092160)\n            └── my_function.d (local) (id=4345092160) (root)\n```\n\nIn this case the list instance is referenced directly by a local variable called `a`, and also\nvia an entry in a dictionary, which is in turn referenced by a local variable called `d`.\n\nNote: this package is experimental and may not work in all cases. It may also be inefficient\nin certain cases, and should not be used in performance-critical code.\n\n## Installation\n\nInstall using pip:\n\n```bash\npip3 install referrers\n```\n\n## Usage\n\nUse the `referrers.get_referrer_graph` function to get a graph of referrers for\nan object.\n\nFor example, get the graph of referrers for the object referenced by `my_variable`:\n\n```python\nimport referrers\n\nreferrer_graph = referrers.get_referrer_graph(my_variable)\nprint(referrer_graph)\n```\n\nAlternatively, use the `get_referrer_graph_for_list` function to get a single graph\nfor multiple objects.\n\n## Basic Example\n\nIn this example we find all referrers for an instance of a `list`:\n\n```python\nimport dataclasses\nfrom typing import List\n\nimport referrers\n\n@dataclasses.dataclass\nclass ParentClass:\n    member_variable: List\n\ndef my_func():\n    local_variable = ParentClass([1, 2])\n    print(referrers.get_referrer_graph(local_variable.member_variable))\n\nmy_func()\n```\n\nThis will output something like:\n\n```plaintext\n╙── list (object) (id=4360191168) (target)\n    └── ParentClass.member_variable (instance attribute) (id=4344740512)\n        └── ParentClass (object) (id=4344740512)\n            └── my_func.local_variable (local) (id=4344740512) (root)\n```\n\nIn this case the list instance is referenced by a member variable of `ParentClass`, which\nis in turn referenced by a local variable in the `my_func` function.\n\n## Integration with memory analysis tools\n\nIt is recommended to use the [Memalot](https://pypi.org/project/memalot/) package to find\nmemory leaks. This is by the same author, and uses Referrers to show references to leaking objects.\n\nThis library can also be used with other memory analysis tools. For example, to print the referrers\nof the top 10 largest objects using [Pympler](https://pympler.readthedocs.io/en/latest/):\n\n```python\nfrom pympler import muppy\nimport referrers\n\ndef main():\n    top_10_objects = (muppy.sort(muppy.get_objects()))[-10:]\n    top_10_objects.reverse()\n    \n    for obj in top_10_objects:\n        print(\n            referrers.get_referrer_graph(\n                obj,\n                exclude_object_ids=[id(top_10_objects)],\n            )\n        )\n        \nif __name__ == \"__main__\":\n    main()\n```\n\nNote that this example  `exclude_object_ids` to exclude the `top_10_objects`\nvariable from the graph.\n\n## Performance\n\nFinding referrers can be slow for objects with many referrers. Use the following options\nto control the performance of the search:\n\n- `timeout`: The maximum time to spend searching for referrers. If this time is exceeded,\n  a partial graph is returned. Note that this timeout is approximate, and may not be\n  effective if the search is blocked by a long-running operation. The default is `None`\n  which means no timeout. If the timeout is exceeded, the graph will contain a node\n  containing the text \"Timeout of N seconds exceeded\".\n- `max_depth`: The maximum depth to search for referrers. The default is 20. Specify\n  `None` to search to unlimited depth (but be careful with this: it may take a long time).\n  If the maximum depth is exceeded, the graph will contain a node containing the text\n  \"Maximum depth of N exceeded\".\n- `max_untracked_search_depth`: The maximum depth to search for referrers of untracked\n  objects. This is the depth that referents will be searched from the roots (locals and\n  globals). The default is 30. If you are missing referrers of untracked objects, you\n  can increase this value.\n- `single_object_referrer_limit`: The maximum number of referrers to include in the graph\n  for an individual object instance. If the limit is exceeded, the graph will contain a\n  node containing the text \"Referrer limit of N exceeded\". Note that this limit is\n  approximate and does not apply to all referrer types. Specifically, it only applies to\n  object references. Additionally, this limit does not apply to immortal objects.\n\n## Integration with NetworkX\n\nThe graph produced by `get_referrer_graph` can be converted to a NetworkX graph using\nits `to_networkx` method. This can be useful for visualizing the graph, or for\nperforming more complex analysis.\n\nThe resulting NetworkX graph consists of nodes of type `ReferrerGraphNode`, with edges\ndirected from referrers to their referents.\n\nFor example, to visualize a graph of references to an object using [NetworkX](https://networkx.org/)\nand [Matplotlib](https://matplotlib.org/):\n\n```python\nimport matplotlib.pyplot as plt\nimport networkx as nx\nimport dataclasses\nimport referrers\n\nclass ChildClass:\n    pass\n\n@dataclasses.dataclass\nclass ContainerClass:\n    instance_attribute: ChildClass\n\ndef node_label(node: referrers.ReferrerGraphNode) -\u003e str:\n    return f\"{node.name.replace(\" \", \"\\n\", 1)}\"\n\ndef my_function():\n    local_variable = ContainerClass(ChildClass())\n    other_variable = ContainerClass(local_variable.instance_attribute)\n    graph = referrers.get_referrer_graph(local_variable.instance_attribute)\n    \n    nx_graph = graph.to_networkx()\n    nx.draw_networkx(\n        nx_graph,\n        pos=nx.spectral_layout(nx_graph),\n        with_labels=True,\n        font_size=8,\n        labels={node: node_label(node) for node in nx_graph.nodes},\n        node_color=\"lightblue\",\n        node_size=1400,\n    )\n    plt.margins(x=0.2)\n    plt.show()\n\nmy_function()\n```\n\nThis will produce an image like this:\n\n\u003cimg width=\"740\" height=\"438\" alt=\"image\" src=\"https://github.com/user-attachments/assets/e1fd9220-e2c9-4a33-a508-3cc5da1876ab\" /\u003e\n\n\n\n\n## Multi-threading\n\nReferrers works well with multiple threads. For example, you can have a separate thread that\nprints the referrers of objects that have references in other threads.\n\nIn the following example, there is a thread that prints the referrers of all instances of\n`ChildClass` every second (using [Pympler](https://pympler.readthedocs.io/en/latest/) to find\nthe instances):\n\n```python\nimport dataclasses\nimport threading\nfrom time import sleep\nfrom pympler import muppy\n\nimport referrers\n\nclass ChildClass:\n    pass\n\n@dataclasses.dataclass\nclass ContainerClass:\n    instance_attribute: ChildClass\n\ndef print_referrers():\n    while True:\n        all_instances = [obj for obj in muppy.get_objects() if isinstance(obj, ChildClass)]\n        print(referrers.get_referrer_graph_for_list(all_instances))\n        sleep(1)\n\nprinting_thread = threading.Thread(target=print_referrers, daemon=True)\nprinting_thread.start()\n\ndef my_function():\n    child_variable = ChildClass()\n    container_variable = ContainerClass(child_variable)\n    sleep(1000)\n\nmy_function()\n```\n\n## Untracked Objects\n\nThis library will try to find referrers for objects that are not tracked by the garbage\ncollector. For example, mutable objects, and collections containing only immutable objects in\nCPython. However, this may be slower than for tracked objects, and is limited by the\n`max_untracked_search_depth` parameter. Try setting this to a higher value if you think there\nare referrers missing from the graph.\n\nFor example, here we find the referrers of an untracked object (a `dict` containing only\nimmutable objects):\n\n```python\nimport dataclasses\nimport gc\nfrom typing import Dict\n\nimport referrers\n\n@dataclasses.dataclass\nclass ParentClass:\n    member_variable: Dict\n\ndef my_func():\n    local_variable = ParentClass({\"a\": 1})\n    assert not gc.is_tracked(local_variable.member_variable)\n    print(referrers.get_referrer_graph(local_variable.member_variable))\n\nmy_func()\n```\n\nThis will output something like:\n\n```plaintext\n╙── dict (object) (id=4374433472) (target)\n    └── ParentClass.member_variable (instance attribute) (id=4381605040)\n        └── ParentClass (object) (id=4381605040)\n            └── my_func.local_variable (local) (id=4381605040) (root)\n```\n\n## Source\n\nSee [https://github.com/nfergu/referrers](https://github.com/nfergu/referrers) for the Github repo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfergu%2Freferrers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnfergu%2Freferrers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnfergu%2Freferrers/lists"}