{"id":16168873,"url":"https://github.com/andrewgazelka/smart-cache","last_synced_at":"2025-08-13T23:04:02.634Z","repository":{"id":57468532,"uuid":"357702517","full_name":"andrewgazelka/smart-cache","owner":"andrewgazelka","description":"🗃 Python caching library that is persistent and uses bytecode analysis to determine re-evaluation","archived":false,"fork":false,"pushed_at":"2024-03-27T17:58:39.000Z","size":51,"stargazers_count":16,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-11T02:48:29.318Z","etag":null,"topics":["caching","python-decorators","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrewgazelka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2021-04-13T22:16:51.000Z","updated_at":"2025-04-09T10:18:17.000Z","dependencies_parsed_at":"2024-10-27T19:19:29.017Z","dependency_job_id":"19499d70-3d36-4311-82cd-22b047c762ab","html_url":"https://github.com/andrewgazelka/smart-cache","commit_stats":{"total_commits":32,"total_committers":1,"mean_commits":32.0,"dds":0.0,"last_synced_commit":"173e8df81beb35cc1996f02324fa987df8a15b9b"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/andrewgazelka/smart-cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewgazelka%2Fsmart-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewgazelka%2Fsmart-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewgazelka%2Fsmart-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewgazelka%2Fsmart-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrewgazelka","download_url":"https://codeload.github.com/andrewgazelka/smart-cache/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewgazelka%2Fsmart-cache/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270330595,"owners_count":24565816,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["caching","python-decorators","python3"],"created_at":"2024-10-10T03:13:33.364Z","updated_at":"2025-08-13T23:04:02.568Z","avatar_url":"https://github.com/andrewgazelka.png","language":"Python","readme":"\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"700\" src=\"https://user-images.githubusercontent.com/7644264/114815257-78e8e800-9d7b-11eb-8a59-ebd6181e916e.gif\"\u003e\n\u003c/p\u003e\n\n\n# Smart Cache\n\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/smart-cache.svg)](https://pypi.python.org/pypi/smart-cache/)\n[![PyPI version shields.io](https://img.shields.io/pypi/v/smart-cache.svg)](https://pypi.python.org/pypi/smart-cache/)\n![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)\n\n\u003csub\u003e\u003csup\u003eThis is not production ready! There are still likely many bugs and there are several performance improvements which can be made\u003c/sup\u003e\u003c/sub\u003e\n\nIntroducing smart cache—apply the `@smart_cache` decorator and all inputs\nwith the same hash will be cached cross-run. Furthermore,\n**the cache will be invalidated if the method bytecode OR the bytecode of method dependencies changes**. This allows for fast rapid prototyping. You do not have to focus on which\nfunctions have been changed, _Smart Cache_ does the work for you.\n\nThe only thing to pay attention to is that your functions are *pure*! This \u003csub\u003e\u003csup\u003ebasically\u003c/sub\u003e\u003c/sup\u003e means that the same input arguments will always yield the same result.  If this isn't the case, then don't include the `@smart_cache` decorator on that function—it can't be cached!\n\n## Installation\n\n```bash\npip3 install smart-cache\n```\n\nMake sure to execute\n```bash\nexport PYTHONHASHSEED=0\n```\nas [hashes are by default salted](https://docs.python.org/3/using/cmdline.html#cmdoption-R).\n\n## Benchmarks\nLet's benchmark the times between cached and non-cached versions of recursive fibonacci.\n```python\n@smart_cache\ndef fib(n):\n    if n == 0:\n        return 0\n    if n == 1:\n        return 1\n    return fib(n - 1) + fib(n - 2)\n\n\ndef bad_fib(n):\n    if n == 0:\n        return 0\n    if n == 1:\n        return 1\n    return bad_fib(n - 1) + bad_fib(n - 2)\n\n\nif __name__ == \"__main__\":\n    start = time.time()\n    cached_result = fib(40)\n    end = time.time()\n\n    print(\"total time cached: {:.2f}ms\".format((end - start) * 1000))\n\n    start = time.time()\n    actual_result = bad_fib(40)\n    end = time.time()\n    print(\"total time uncached: {:.2f}ms\".format((end - start) * 1000))\n\n    difference = actual_result - cached_result\n    print(\"difference: \", difference)\n```\n\nThe first run (without any previous caching) we get times of\n```\ntotal time cached: 0.58ms\ntotal time uncached: 31840.58ms\ndifference:  0\n```\n\nThe second time will be even faster—we only need one lookup since `fib(40)` is cached. We get\n```\ntotal time cached: 0.48ms\ntotal time uncached: 31723.69ms\ndifference:  0\n```\n\n## Simple Example\nSuppose we run\n```python\ndef abc():\n    x = 2+2\n    return x\n\n\n@smart_cache\ndef tester():\n    return 1 + abc()\n\n\nif __name__ == \"__main__\":\n    print(tester())\n```\n\nOnly the first time we run this will\nresults not be cached.\n\nSuppose we make a modification to `abc`\n\n```python\ndef abc():\n    x = 2+3\n    return x\n```\n\nAll caches will be invalidated. However, if `abc` were\nchanged to\n\n```python\ndef abc():\n    # this is a comment\n    x = 2+2\n    return x\n```\n\nThe cache will not be invalidated because even though the \ncode changes—none of the byte code changes.\n\nSimilary if we add another function `xyz()`,\n\n```python\n\ndef xyz(a_param):\n    return a_param*2\n```\n\nThe cache will _also_ NOT be invalidated because although\nthe bytecode of the file changes, the bytecode of neither the function `tester`\nnor its dependencies change.\n\n## Recursive Functions\nRecursive functions also work as expected!\n```python\n@smart_cache\ndef fib(n):\n    if n == 0:\n        return 0\n    if n == 1:\n        return 1\n    return fib(n - 1) + fib(n - 2)\n\n\nif __name__ == \"__main__\":\n    print(fib(6))\n```\n\nwill run in `O(n)` time when it is first run\nand `O(1)` the time after that.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewgazelka%2Fsmart-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrewgazelka%2Fsmart-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewgazelka%2Fsmart-cache/lists"}