{"id":32649684,"url":"https://github.com/seperman/redisworks","last_synced_at":"2025-10-31T06:57:04.220Z","repository":{"id":10581387,"uuid":"66236211","full_name":"seperman/redisworks","owner":"seperman","description":"Pythonic Redis Client","archived":false,"fork":false,"pushed_at":"2023-03-31T15:27:59.000Z","size":63,"stargazers_count":98,"open_issues_count":5,"forks_count":12,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-30T16:56:11.881Z","etag":null,"topics":["lazy-redis-queries","python","redis","redis-client"],"latest_commit_sha":null,"homepage":"http://www.zepworks.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seperman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["seperman"],"ko_fi":"seperman"}},"created_at":"2016-08-22T03:20:27.000Z","updated_at":"2025-05-19T10:04:45.000Z","dependencies_parsed_at":"2024-06-19T17:39:46.946Z","dependency_job_id":"9a01eec6-ad51-4b28-b06d-ff3ad901f7db","html_url":"https://github.com/seperman/redisworks","commit_stats":{"total_commits":60,"total_committers":5,"mean_commits":12.0,"dds":0.2666666666666667,"last_synced_commit":"a69675cbafae374d710fb030d27fb12948cddafa"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/seperman/redisworks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seperman%2Fredisworks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seperman%2Fredisworks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seperman%2Fredisworks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seperman%2Fredisworks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seperman","download_url":"https://codeload.github.com/seperman/redisworks/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seperman%2Fredisworks/sbom","scorecard":{"id":811630,"data":{"date":"2025-08-11","repo":{"name":"github.com/seperman/redisworks","commit":"a69675cbafae374d710fb030d27fb12948cddafa"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Code-Review","score":5,"reason":"Found 4/7 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/seperman/redisworks/main.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:20: update your workflow using https://app.stepsecurity.io/secureworkflow/seperman/redisworks/main.yaml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yaml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/seperman/redisworks/main.yaml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yaml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/seperman/redisworks/main.yaml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/main.yaml:36","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   1 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2023-45 / GHSA-24wv-mv5m-xv4h","Warn: Project is vulnerable to: PYSEC-2023-46 / GHSA-8fww-64cx-x8p5"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-23T13:20:36.629Z","repository_id":10581387,"created_at":"2025-08-23T13:20:36.629Z","updated_at":"2025-08-23T13:20:36.629Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281946311,"owners_count":26587973,"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-10-31T02:00:07.401Z","response_time":57,"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":["lazy-redis-queries","python","redis","redis-client"],"created_at":"2025-10-31T06:56:43.159Z","updated_at":"2025-10-31T06:57:04.215Z","avatar_url":"https://github.com/seperman.png","language":"Python","funding_links":["https://github.com/sponsors/seperman","https://ko-fi.com/seperman"],"categories":[],"sub_categories":[],"readme":"# Redisworks 0.4.0\n\n![Python Versions](https://img.shields.io/pypi/pyversions/redisworks.svg?style=flat)\n![License](https://img.shields.io/pypi/l/redisworks.svg?version=latest)\n[![Build Status](https://travis-ci.org/seperman/redisworks.svg?branch=master)](https://travis-ci.org/seperman/redisworks)\n[![Coverage Status](https://coveralls.io/repos/github/seperman/redisworks/badge.svg?branch=master)](https://coveralls.io/github/seperman/redisworks?branch=master)\n\n**The Pythonic Redis Client**\n\nWhy Redisworks?\n\n- Lazy Redis Queries\n- Dynamic Typing\n- Ease of use\n\nHave you ever used PyRedis and wondered why you have to think about types all the time? That you have to constantly convert objects to strings and back and forth since Redis keeps most things as strings?\n\nRedis works provides a Pythonic interface to Redis. Let Redisworks take care of type conversions for you.\n\nBehind the scene, Redisworks uses [DotObject](https://github.com/seperman/dotobject) to provide beautiful dot notation objects and lazy Redis queries.\n\n# Install\n\n`pip install redisworks`\n\nNote that RedisWorks needs Redis server 2.4+.\n\n# Setup\n\nlet's say if you want all the keys in Redis to start with the word `root`.\nThen you:\n\n```py\nroot = Root()  # connects to Redis on local host by default\n```\n\nOr if you want to be more specific:\n\n```py\nroot = Root(host='localhost', port=6379, db=0)\n```\n\n## password\n\nAny other parameter that you pass to Root will be passed down to PyRedis. For example:\n\n```py\nroot = Root(host='localhost', port=6379, db=0, password='mypass')\n```\n\n\n# Saving to Redis\n\nSaving to Redis is as simple as assigning objects to attributes of root or attributes of attributes of root (you can go as deep as you want.)\nMake sure you are not using any Python's reserved words in the key's name.\n\nExample:\n\n```py\n\u003e\u003e\u003e from redisworks import Root\n\u003e\u003e\u003e import datetime\n\u003e\u003e\u003e root = Root()\n\u003e\u003e\u003e root.my.list = [1, 3, 4]\n\u003e\u003e\u003e root.my.other.list = [1, [2, 2]]\n\u003e\u003e\u003e \n\u003e\u003e\u003e some_date = datetime.datetime(2016, 8, 22, 10, 3, 19)\n\u003e\u003e\u003e root.time = some_date\n\u003e\u003e\u003e \n\u003e\u003e\u003e root.the.mapping.example = {1:1, \"a\": {\"b\": 10}}\n```\n\nRedis works will automatically convert your object to the proper Redis type and immediately write it to Redis as soon as you assign an element!\n\nThe respective keys for the above items will be just like what you type: `root.my.list`, `root.time`, `root.the.mapping.example`:\n\nIf you use redis-cli, you will notice that the data is saved in the proper Redis data type:\n\n```\n127.0.0.1:6379\u003e scan 0\n1) \"0\"\n2) 1) \"root.the.mapping.example\"\n   2) \"root.time\"\n   3) \"root.my.list\"\n127.0.0.1:6379\u003e type root.the.mapping.example\nhash\n127.0.0.1:6379\u003e type root.time\nstring\n127.0.0.1:6379\u003e type root.my.list\nlist\n```\n\n# Reading from Redis\n\nReading the data is as simple as if it was just saved in Python memory!\n\nRedis works returns Lazy queries just like how Django returns lazy queries. In fact the lazy objects code is borrowed from Django!\n\nIf you ran the example from [Saving to Redis](#saving-to-redis), run a flush `root.flush()` to empty Redisworks Cache. This is so it goes and gets the objects from Redis instead of reading its own current copy of data:\n\n```py\n\u003e\u003e\u003e from redisworks import Root\n\u003e\u003e\u003e root = Root()\n\u003e\u003e\u003e thetime = root.time\n\u003e\u003e\u003e thelist = root.my.list\n\u003e\u003e\u003e mydict = root.the.mapping.example\n\u003e\u003e\u003e mydict  # is not evalurated yet!\n\u003cLazy object: root.the.mapping.example\u003e\n\u003e\u003e\u003e print(mydict)\n{1:1, \"a\": {\"b\": 10}}  # Now all the 3 objects are read from Redis!\n\u003e\u003e\u003e mydict\n{1:1, \"a\": {\"b\": 10}}\n\u003e\u003e\u003e root.my.list\n[1, 3, 4]\n\u003e\u003e\u003e root.my.other.list\n[1, [2, 2]]\n\u003e\u003e\u003e root.time\n2016-08-22 10:03:19\n```\n\n# Changing root key name\n\nEvery key name by default starts with the word `root`.\nIf you want to use another name, you have two options:\n\nOption 1, pass a namespace:\n\n```py\n\u003e\u003e\u003e mynamespace = Root(conn=redis_conn, namespace='mynamespace')\n\u003e\u003e\u003e mynamespace.foo = 'bar'\n```\n\nOption 2, simply subclass `Root`:\n\n```py\n\u003e\u003e\u003e from redisworks import Root\n\u003e\u003e\u003e class Post(Root):\n...     pass\n\u003e\u003e\u003e post=Post()\n\u003e\u003e\u003e post.item1 = \"something\"  # saves to Redis\n...\n\u003e\u003e\u003e print(post.item1)  # loads from Redis\nsomething\n```\n\n# Numbers as attribute names\n\nLet's say you want `root.1` as a key name.\nPython does not allow attribute names start with numbers.\n\nAll you need to do is start the number with the character `i` so Redisworks takes care of it for you:\n\n```py\n\u003e\u003e\u003e root.i1 = 10\n\u003e\u003e\u003e print(root.i1)\n10\n```\n\nThe actual key in Redis will be `root.1`\n\n# Dynamic key names\n\n```py\n\u003e\u003e\u003e path1 = 'blah'\n\u003e\u003e\u003e path2 = 'blah.here`'\n\n\u003e\u003e\u003e root[path1] = 'foo'\n\u003e\u003e\u003e root[path2] = 'foo bar'\n\n\u003e\u003e\u003e root.blah\nfoo\n\u003e\u003e\u003e root.blah.here\nfoo bar\n```\n\n\n# Passing TTL to the keys\n\nYou can use the `with_ttl` helper.\n\n```py\n\u003e\u003e\u003e from redisworks import Root, with_ttl\n\u003e\u003e\u003e self.root.myset = with_ttl([1, 2, 3], ttl=1)\n\u003e\u003e\u003e self.root.flush()\n\u003e\u003e\u003e self.root.myset\n[1, 2, 3]\n\u003e\u003e\u003e time.sleep(1.2)\n\u003e\u003e\u003e self.root.flush()\n\u003e\u003e\u003e self.root.myset\n\n```\n\n\n# Other examples\n\nTake a look at [example.py](example.py)\n\n# Primary Author\n\nSeperman (Sep Dehpour)\n\n- [Github](https://github.com/seperman)\n- [Linkedin](http://www.linkedin.com/in/sepehr)\n- [ZepWorks](https://zepworks.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseperman%2Fredisworks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseperman%2Fredisworks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseperman%2Fredisworks/lists"}