{"id":13494208,"url":"https://github.com/pinetr2e/napkin","last_synced_at":"2025-10-21T19:42:12.702Z","repository":{"id":23659851,"uuid":"27030611","full_name":"pinetr2e/napkin","owner":"pinetr2e","description":"Python as DSL for writing PlantUML sequence diagrams","archived":false,"fork":false,"pushed_at":"2021-07-18T07:21:38.000Z","size":409,"stargazers_count":200,"open_issues_count":2,"forks_count":11,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-09-07T09:57:08.107Z","etag":null,"topics":["plantuml-generator","python","uml-sequence-diagram"],"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/pinetr2e.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2014-11-23T11:43:17.000Z","updated_at":"2025-07-12T00:53:51.000Z","dependencies_parsed_at":"2022-08-05T23:00:12.971Z","dependency_job_id":null,"html_url":"https://github.com/pinetr2e/napkin","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/pinetr2e/napkin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinetr2e%2Fnapkin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinetr2e%2Fnapkin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinetr2e%2Fnapkin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinetr2e%2Fnapkin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pinetr2e","download_url":"https://codeload.github.com/pinetr2e/napkin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pinetr2e%2Fnapkin/sbom","scorecard":{"id":734292,"data":{"date":"2025-08-11","repo":{"name":"github.com/pinetr2e/napkin","commit":"fb1da3d3b3b9fceb59a4adc1287a93393d0baa4c"},"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":"Code-Review","score":0,"reason":"Found 0/28 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":"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/release-package.yml:1","Warn: no topLevel permission defined: .github/workflows/test.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":"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/release-package.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/pinetr2e/napkin/release-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release-package.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/pinetr2e/napkin/release-package.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release-package.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/pinetr2e/napkin/release-package.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/pinetr2e/napkin/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/pinetr2e/napkin/test.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/release-package.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/release-package.yml:22","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:21","Warn: pipCommand not pinned by hash: .github/workflows/test.yml:22","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   4 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":"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":"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":"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":"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":"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-22T15:17:44.994Z","repository_id":23659851,"created_at":"2025-08-22T15:17:44.994Z","updated_at":"2025-08-22T15:17:44.994Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280325269,"owners_count":26311417,"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-21T02:00:06.614Z","response_time":58,"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":["plantuml-generator","python","uml-sequence-diagram"],"created_at":"2024-07-31T19:01:22.895Z","updated_at":"2025-10-21T19:42:12.665Z","avatar_url":"https://github.com/pinetr2e.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"![Build Status](https://github.com/pinetr2e/napkin/actions/workflows/test.yml/badge.svg)\n[![PyPI version](https://badge.fury.io/py/napkin.svg)](https://badge.fury.io/py/napkin)\n# Napkin\n\nNapkin is a tool to \"write\" sequence diagrams effectively as Python code.\n\n\n## Motivation\nThe sequence diagrams are useful tool to capture the behavioural aspect of the\ndesign. [PlantUML](http://plantuml.com) is a great tool to draw nice sequence\ndiagrams with simple human readable plain text.\n\nHowever, the syntax of PlantUML is hard to use when there are nested calls,\nwhere lifeline with multiple activation/deactivation are involved.\nUnfortunately, this situation is quite common in sequence diagram for S/W.\n\nFor example, consider the following common sequence diagram,\nwhich is from [Figure 4.2, UML Distilled 3E](https://my.safaribooksonline.com/book/software-engineering-and-development/uml/0321193687/sequence-diagrams/ch04):\n![Figure 4.2, UML Distilled 3E](images/distributed_control.png)\n\nThe PlainUML script for the diagram will be as follows:\n```plantuml\n@startuml\nparticipant User\nparticipant Order\nparticipant OrderLine\nparticipant Product\nparticipant Customer\n\nUser -\u003e Order : calculatePrice()\nactivate Order\nOrder -\u003e OrderLine : calculatePrice()\nactivate OrderLine\nOrderLine -\u003e Product : getPrice(quantity:number)\nOrderLine -\u003e Customer : getDiscountedValue(Order)\nactivate Customer\nCustomer -\u003e Order : getBaseValue()\nactivate Order\nCustomer \u003c-- Order: value\ndeactivate Order\nOrderLine \u003c-- Customer: discountedValue\ndeactivate Customer\ndeactivate OrderLine\ndeactivate Order\n@enduml\n```\nIt is quite hard to follow especially as there are multiple level of nested activation/deactivation.\n\nWhat if we express the same thing as the following Python code ?\n```python\n\n@napkin.seq_diagram()\ndef distributed_control(c):\n    user = c.object('User')\n    order = c.object('Order')\n    orderLine = c.object('OrderLine')\n    product = c.object('Product')\n    customer = c.object('Customer')\n\n    with user:\n        with order.calculatePrice():\n            with orderLine.calculatePrice():\n                product.getPrice('quantity:number')\n                with customer.getDiscountedValue(order):\n                    order.getBaseValue().ret('value')\n                    c.ret('discountedValue')\n```\n`distributed_control` is normal function accepting a context object, `c` to access APIs.\nThe function defines objects and the control starts with `user` object, which then calls `orderLine.calculatePrice()`.\nBasically, the sequence diagram is expressed as \"almost\" normal python code.\n\nThere are several advantages in using Python instead of using other special\nsyntax language:\n* Easy to write/maintain scripts for the correct diagrams\n* Many common mistakes are detected as normal Python error. For example, method\n  call to an undefined object will be just normal Python error.(This can be even\n  checked by IDE without running scripts).\n* Any Python editor can become sequence diagram editor\n* There can be many interesting usages by taking advantage of Python as general\n  language. For example, we can build a library for patterns.\n\n\n## Installation\n\nInstall and update using `pip`\n```shell\n$ pip install napkin\n```\n\n## Hello world\n\nWrite a simple script called `hello.py` as follows:\n\n```python\nimport napkin\n\n@napkin.seq_diagram()\ndef hello_world(c):\n    user = c.object('user')\n    world = c.object('world')\n    with user:\n        world.hello()\n```\nThen, the following command will generate `hello_world.puml`:\n```shell\n$ napkin hello.py\n```\n\n## Usages\n\n### Command line\n```\nusage: napkin [-h] [--output-format {plantuml,plantuml_png,plantuml_svg,plantuml_txt}] [--output-dir DIR] [--version] [--raw-header-file FILE]\n              [--server-url URL]\n              srcs [srcs ...]\n\nGenerate UML sequence diagram from Python code\n\npositional arguments:\n  srcs                  Python file or directory containing diagram functions\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --output-format {plantuml,plantuml_png,plantuml_svg,plantuml_txt}, -f {plantuml,plantuml_png,plantuml_svg,plantuml_txt}\n  --output-dir DIR, -o DIR\n  --version             show program's version number and exit\n  --raw-header-file FILE, -H FILE\n                        file to copy its contents right after @startuml. It is mainly for changing styles\n  --server-url URL      (only for plantuml_png/svg/txt format) Default is the public server\n\nSupported output formats:\n  plantuml         : PlantUML script (default)\n  plantuml_png     : PlantUML script and PNG image\n  plantuml_svg     : PlantUML script and SVG image\n  plantuml_txt     : PlantUML script and ASCII art text\n```\n\n### Standalone code to generate diagrams\n\nInstead of passing `napkin` binary Python files, we can generate diagrams simply by running\nthe Python source code containing the diagrams as follows:\n```python\n\nimport napkin\n\n@napkin.seq_diagram()\ndef hello_world(c):\n    ...\n\n\nif __name__ == '__main__':\n    napkin.generate()\n```\n`napkin.generate(output_format='plantuml', output_dir='.')` will generate all the diagrams described in the same file.\n\n\n### Generate image files using PlantUML server\n\nNapkin can generate PNG/SVG image or ASCII art text files by asking PlantUML\nserver.\n\nIn order to generate image file, image format needs to be specified as `plantuml_\u003cpng|svg|txt\u003e`, which will generate image file along with puml file.\n```shell\n$ napkin -f plantuml_png hello.py\n```\n\nAs default, the public server is used and it can be changed by `--server-url`.\n\n## Python script examples\nMost usage examples are available [here](./DEMO_EXAMPLES.md).\n\n## Changelogs\nA new feature or fix will be avaialbe [here](CHANGELOG.md).\n\n## Misc\n\n### Helper tool to convert PlantUML text files to image files\nAs Napkin has a functionality to generate image files from PlantUML text file, a\nsimple script, `napkin_plantuml` is provided to use PlantUML server to generate\nimages.\n\nFor example, in order to generate `hello.png` image from `hello.puml` file:\n```shell\n$ napkin_plantuml hello.puml hello.png\n```\n### Emacs org babel support\n\nIn order to use `napkin` as literate programming tool [ob-napkin\npackage](https://github.com/pinetr2e/ob-napkin) is supported for Emacs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinetr2e%2Fnapkin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpinetr2e%2Fnapkin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpinetr2e%2Fnapkin/lists"}