{"id":15445152,"url":"https://github.com/ccubed/earl","last_synced_at":"2025-08-20T10:26:30.289Z","repository":{"id":57424993,"uuid":"70570071","full_name":"ccubed/Earl","owner":"ccubed","description":"Earl is the fanciest C++ extension for Python that allows External Term Format packing and unpacking.","archived":false,"fork":false,"pushed_at":"2017-11-20T00:42:35.000Z","size":582,"stargazers_count":6,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-07-27T16:05:39.530Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","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/ccubed.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":"2016-10-11T08:00:25.000Z","updated_at":"2023-01-22T02:37:07.000Z","dependencies_parsed_at":"2022-09-13T15:23:18.430Z","dependency_job_id":null,"html_url":"https://github.com/ccubed/Earl","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ccubed/Earl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccubed%2FEarl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccubed%2FEarl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccubed%2FEarl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccubed%2FEarl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ccubed","download_url":"https://codeload.github.com/ccubed/Earl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ccubed%2FEarl/sbom","scorecard":{"id":269416,"data":{"date":"2025-08-11","repo":{"name":"github.com/ccubed/Earl","commit":"7c29cbd853623150a5ad1c9b49d40fa106c640f4"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"Code-Review","score":1,"reason":"Found 3/27 approved changesets -- score normalized to 1","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":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"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":"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":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"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":"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":"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":"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"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 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-17T12:57:55.755Z","repository_id":57424993,"created_at":"2025-08-17T12:57:55.756Z","updated_at":"2025-08-17T12:57:55.756Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271302166,"owners_count":24735961,"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-20T02:00:09.606Z","response_time":69,"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":[],"created_at":"2024-10-01T19:44:07.596Z","updated_at":"2025-08-20T10:26:30.213Z","avatar_url":"https://github.com/ccubed.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Earl\nEarl is the fanciest C++ extension for Python that allows External Term Format packing and unpacking.\nThis library can support packing and unpacking the External Term Format made popular by Erlang in Python. Written in C++ using the Python C API, it should be\nmarginally usable across the various Python implementations, but for now I can guarantee CPython because that's what it was built against.\n\nI have tested that the ETF this produces works with binary_to_term in Erlang.\n\n# Installation\n```\npip install Earl-ETF\n```\n\n# Usage\n```Python\nimport earl\na = earl.pack([1,2,3])\nearl.unpack(a)\n```\n## Functions\nThere are only two. Pack and Unpack. Give pack anything you want to convert to External Term Format. Give Unpack a bytes object that represents data in External Term Format to get back Python Objects as per below.\n\n# Features\nCurrently Earl supports these features. Earl is written for the latest version of External Term Format as of Erlang 8.2.\n\n## Packing\n* SMALL_INTEGER_EXT\n* INTEGER_EXT\n* SMALL_TUPLE_EXT\n* LARGE_TUPLE_EXT\n* LIST_EXT\n* STRING_EXT\n* MAP_EXT\n* ATOM_UTF8_EXT\n* NIL_EXT\n\n### Python Types to Pack Types\nThis is a list of Python types and the corresponding ETF type they are converted to.\n\n* Integers \u003c 256: SMALL_INTEGER_EXT\n* Integers \u003e= 256: INTEGER_EXT\n* String/Unicode: ATOM_UTF8\n* Bytes: STRING_EXT (If more than 65535, LIST_EXT)\n* Dictionary: MAP_EXT\n* Tuple: SMALL_TUPLE_EXT/LARGE_TUPLE_EXT (Depending on Size)\n* Lists/Sets: LIST_EXT\n* None: An Atom with the name nil\n* True/False: Atoms with the same name\n* Empty List ([]): In Erlang, Nil() is a special value representing the empty list. In ETF it is represented by NIL_EXT. If you pass an empty list Earl will return NIL_EXT.\n\n## Unpacking\n* SMALL_INTEGER_EXT\n* INTEGER_EXT\n* SMALL_TUPLE_EXT\n* LARGE_TUPLE_EXT\n* LIST_EXT\n* STRING_EXT\n* MAP_EXT\n* ATOM_UTF8_EXT\n* SMALL_ATOM_UTF8_EXT\n* ATOM_EXT\n* BINARY_EXT\n\n### Some notes about unpacking\n* You can only provide unpack one bytes object. It does not unpack many bytes objects.\n* They are converted to python types according to the list above under packing.\n* Maps are slow to parse because they are parsed independently in order to retain depth. I could make this faster by ignoring depth, but that defeats the purpose of a map.\n\n# So how fast is this\nThis code is C++ accessing individual bytes, which means it is fairly fast. Overall, the speed depends on how many items you ask it to unpack or pack and how complex each item is. This is to be expected. Depending on that, the speeds can range from nanoseconds to microseconds.\n\n## Actual Benchmarks\nBenchmarks updated as of 1.7.\n\n# Packing\n```\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack(120)\"\n10000000 loops, best of 3: 0.179 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack(12000)\"\n10000000 loops, best of 3: 0.183 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack((1,2,3))\"\n1000000 loops, best of 3: 0.32 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack([1,2,3])\"\n1000000 loops, best of 3: 0.371 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack({1,2,3})\"\n1000000 loops, best of 3: 0.422 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"earl.pack({1:2, 3:4})\"\n1000000 loops, best of 3: 0.532 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl\" \"a=earl.pack({1:{'d':[1,2,3], '_trace': 12000}})\"\n1000000 loops, best of 3: 1.31 usec per loop\n```\n\n# Unpacking\n```\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack(120)\" \"earl.unpack(a)\"\n10000000 loops, best of 3: 0.185 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack(12000)\" \"earl.unpack(a)\"\n10000000 loops, best of 3: 0.201 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack((1,2,3))\" \"earl.unpack(a)\"\n1000000 loops, best of 3: 0.247 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack([1,2,3])\" \"earl.unpack(a)\"\n1000000 loops, best of 3: 0.262 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack({1,2,3})\" \"earl.unpack(a)\"\n1000000 loops, best of 3: 0.27 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack({1:2, 3:4})\" \"earl.unpack(a)\"\n1000000 loops, best of 3: 0.614 usec per loop\n\nclick@DESKTOP-QL2J54T C:\\Users\\click\\Documents\\GitHub\\Earl\n\u003e python -m timeit --setup=\"import earl;a=earl.pack({1:{'d':[1,2,3], '_trace': 12000}})\" \"earl.unpack(a)\"\n1000000 loops, best of 3: 1.24 usec per loop\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccubed%2Fearl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fccubed%2Fearl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fccubed%2Fearl/lists"}