{"id":24280681,"url":"https://github.com/kneasle/belltower","last_synced_at":"2026-05-30T18:31:05.264Z","repository":{"id":57414604,"uuid":"333991429","full_name":"kneasle/belltower","owner":"kneasle","description":"A super-simple Python library for interacting with Ringing Room.","archived":false,"fork":false,"pushed_at":"2021-02-13T00:41:59.000Z","size":63,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-12-04T05:22:25.115Z","etag":null,"topics":["bellringing","library","python","ringing-room"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kneasle.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}},"created_at":"2021-01-29T00:18:11.000Z","updated_at":"2021-05-09T08:47:55.000Z","dependencies_parsed_at":"2022-09-27T10:50:28.463Z","dependency_job_id":null,"html_url":"https://github.com/kneasle/belltower","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/kneasle/belltower","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fbelltower","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fbelltower/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fbelltower/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fbelltower/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kneasle","download_url":"https://codeload.github.com/kneasle/belltower/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kneasle%2Fbelltower/sbom","scorecard":{"id":564396,"data":{"date":"2025-08-11","repo":{"name":"github.com/kneasle/belltower","commit":"a8016b3adf3cd0202fa1323fd7d83f00406c11f5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"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":"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":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/publish-to-pypi.yml: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":"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/publish-to-pypi.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/kneasle/belltower/publish-to-pypi.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/publish-to-pypi.yml:19","Warn: pipCommand not pinned by hash: .github/workflows/publish-to-pypi.yml:20","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 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":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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":"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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"}}]},"last_synced_at":"2025-08-20T14:34:34.404Z","repository_id":57414604,"created_at":"2025-08-20T14:34:34.404Z","updated_at":"2025-08-20T14:34:34.404Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33705207,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-30T02:00:06.278Z","response_time":92,"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":["bellringing","library","python","ringing-room"],"created_at":"2025-01-16T02:25:23.329Z","updated_at":"2026-05-30T18:31:05.246Z","avatar_url":"https://github.com/kneasle.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BellTower\n\nA super-simple Python library for interacting with [Ringing Room](https://ringingroom.com).\n\nThis library is quite W.I.P., and its development is mostly driven by its potential use in\n[Wheatley](https://github.com/kneasle/wheatley) and other (as of yet unreleased) projects of mine.\nThe library seems to be quite stable, but the API could change at any moment whilst I'm developing\nit.\n\nIf you have any queries, then please leave \n[an issue](https://github.com/kneasle/belltower/issues/new).  Pull requests are very welcome, but if\nyou are making any large-scale changes then it may be worth suggesting them in an issue first.\n\n## Get Started\n\nQuickstart and documentation are both\n[here](https://github.com/kneasle/belltower/blob/master/QUICKSTART.md), and examples can be found in\nthe [examples folder](https://github.com/kneasle/belltower/tree/master/examples).\n\n## Why use this simple library?\n\n- Simple libraries are just nicer to use!\n- No knowledge of Ringing Room internals is needed to do cool things with Ringing Room.\n- If the internals of Ringing Room change (which they have done), then fixing those breakages is as\n  simple as changing to the newest version of BellTower.\n- This library doesn't have to be specific to Ringing Room (though Ringing Room is far and away the\n  most popular online ringing platform, so for the time being it is the only supported platform).\n\n## Example: A simple chatbot\n\nA chatbot which, whenever anyone says `Hello` in the chat, replies with `Hello, \u003cusername\u003e`.\n\nMore examples can be found in the \n[examples folder](https://github.com/kneasle/belltower/tree/master/examples), with this example at\n[examples/chatbot.py](https://github.com/kneasle/belltower/blob/master/examples/chatbot.py):\n```python\n# Import the tower class, and 'time.sleep'\nfrom time import sleep\nfrom belltower import RingingRoomTower\n\n# Create a new tower, and tell it to join tower ID 765432918\ntower = RingingRoomTower(765432918)\n\n# Register a function to be called when a chat message is posted\n@tower.on_chat\ndef on_chat(user, message):\n    print(f\"{user} says '{message}'\")\n    # If the message is 'hello' in any capitalisation, send 'Hello \u003cuser\u003e'.\n    # The first argument is the name to put next to the chat message\n    if message.lower() == \"hello\":\n        tower.chat(\"RR ChatBot\", f\"Hello, {user}!\")\n\n# The 'with' block makes sure that 'tower' has a chance to gracefully shut\n# down the connection if the program crashes\nwith tower:\n    # Wait until the tower is loaded\n    tower.wait_loaded()\n    # Go into an infinite loop.  It doesn't matter what the main thread does,\n    # but if it leaves the `with` block then the Tower's connection will\n    # close and become unusable\n    while True:\n        sleep(1000)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkneasle%2Fbelltower","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkneasle%2Fbelltower","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkneasle%2Fbelltower/lists"}