# pycodetags
You've seen `# TODO:` comments? What if they could be used as an issue tracker?
What if `# TODO:` style comments could serialize and deserialize records, turning comments into a database?
[Live example](https://matthewdeanmartin.github.io/pycodetags/).
[//]: # (What if you could also write comments as decorators that warn or stop you on the due date?)
[//]: # ()
[//]: # (Replace or complement your `# TODO:` comments with decorators similar to NotImplement, Deprecated or Warning)
[//]: # (and get issue tracker features, too.)
Lightweight and keeps your issue tracker in your code.
Backwards compatible with folk `# TODO:` comments, which can vary greatly in how people write them.
Core library is for Data Tags, which are abstract and domain free. Plugs have domain-specific tags, e.g. Issue Tracking.
## Installation
For generic code tags strictly in comments (DATA tags):
`pipx install pycodetags`
For code tag decorators, objects, exceptions, context managers with run-time behavior:
`pip install pycodetags`
To get a domain specific data tags (TODO tags), e.g. issue tracker or discussion, install with plugin
`pip install pycodetags pycodetags-issue-tracker`
Requires python 3.7+. 3.7 will probably work.
The only dependencies are `pluggy` and `ast-comments` and backports of python standard libraries to support old versions
of python. For pure-comment style code tags, pipx install and nothing is installed with your application code.
## Usage
`pycodetags` can work with pre-existing comment based code tags, both the folk-schema style and the PEP-350 style.
Ways to track a TODO item
- PEP-350 code tags, e.g. `# TODO: implement game <due=2025-06-01>`
- Folk code tags, e.g. `# TODO(matth): example.com/ticktet=123 implement game`
- ADVANCED: Add a function decorator, e.g. `@TODO("Work on this")`
While you work
- View the issue-tracker-like single page website `pycodetas issues html`
- Exceptions will be raised or logged when overdue
At build and release time
- Fail build on overdue items (as opposed to failing build on the existence of any code tag, as pylint recommends)
- Generate CHANGELOG.md using the keep-a-changelog format
- `pycodetags issues changelog`
- Generate DONE.txt, TODO.md, TODO.html files
- `pycodetags issues todomd`
- `pycodetags issues donefile`
## Example
```python
from pycodetags_issue_tracker import TODO
# Folk schema
# TODO: Implement payments
# PEP 350 Comment
# TODO: Add a new feature for exporting. <assignee:matth priority=1 2025-06-15>
# Attached to function
@TODO(assignee="matth", due="06/01/2025", comment="Implement payment logic")
def unfinished_feature():
print("This should not run if overdue and assignee is Matthew.")
@TODO(status="Done", tracker="https://ticketsystem/123")
def finished_feature():
print("This is a completed feature.")
# Wrapped around any block of code to show what the TODO is referring to
with TODO(comment="Needs Logging, not printing", assignee="carol", due="2025-07-01"):
print(100 / 3)
if __name__ == "__main__":
finished_feature() # won't throw
unfinished_feature() # may throw if over due
```
To generate reports:
```text
❯ pycodetags
usage: pycodetags [-h] [--config CONFIG] [--verbose] [--info] [--bug-trail] {data,plugin-info,issues} ...
TODOs in source code as a first class construct, follows PEP350 (v0.3.0)
positional arguments:
{data,plugin-info,issues}
Available commands
data Generate code tag reports
plugin-info Display information about loaded plugins
issues Reports for TODOs and BUGs
options:
-h, --help show this help message and exit
--config CONFIG Path to config file, defaults to current folder pyproject.toml
--verbose verbose level logging output
--info info level logging output
--bug-trail enable bug trail, local logging
Install pycodetags-issue-tracker plugin for TODO tags.
```
## How it works
Comments with some extra syntax are treated as a data serialization format.
` # DATA: text <default-string default-date default-type data1:value data2:value custom1:value custom2:value`>
Combined with a schema you get a code tag, or a discussion tag, e.g.
`# BUG: Division by zero <MDM 2025-06-06 priority=3 storypoints=5>`
`# QUESTION: Who thought this was a good idea? <MDM 2025-06-06 thread=1 snark=excessive>`
```python
# DATA: text
# text line two
```
- The upper case tag in the `# DATA:` signals the start of a data tag.
- The text continues until a `<>` block terminates or a non-comment line.
- The `<>` block holds space separated key value pairs
- The key is optional, values are optionally unquoted, single or double-quoted
- Key value pairs follow, `key=value` or `key:value`
- default fields are key-less fields identified by their type, e.g. `MDM`, `MDM,JQP`, or `2025-01-01`
- data fields identified by a schema. PEP-350 is one schema. e.g. `assignee:MDM`, `assignee=MDM`
- custom fields are data fields that are not expected by the schema. `program-increment:4`
See docs for handling edge cases.
## Basic Workflow
- Write code with TODOs, DONEs, and other code tags.
- Run `pycodetags issues --validate` to ensure data quality is high enough to generate reports.
- Run `pycodetags issues --format <format>` to generate reports.
- Update tags as work is completed.
## Configuration
No workflow or schema is one-size-fits all, so you will almost certainly want to do some configuration.
The expectation is that this config is used at development time, optionally on the build server and *not* when
deployed to production or an end users machine. If you are using only comment code tags, it is not an issue. There
is a runtime cost or risk only when using strongly typed code tags.
See [documentation](https://pycodetags.readthedocs.io/en/latest/) for details.
## Prior Art
PEPs and Standard Library Prior Art
- [PEP 350 - Code Tags](https://peps.python.org/pep-0350/) Rejected proposal, now implemented, mostly by `pycodetags`
## Project Health
| Metric | Status |
|----------------|--------|
| Coverage | [](https://codecov.io/gh/matthewdeanmartin/pycodetags) |
| Docs | [](https://pycodetags.readthedocs.io/en/latest/) |
| PyPI | [](https://pypi.org/project/pycodetags/) |
| Downloads | [](https://pepy.tech/project/pycodetags) |
| License | [](https://github.com/matthewdeanmartin/pycodetags/blob/main/LICENSE.md) |
| Last Commit |  |
## Libray info pages
- [pycodetags](https://libraries.io/pypi/pycodetags)
- [pycodetags-issue-tracker](https://libraries.io/pypi/pycodetags-issue-tracker) plugin
## Snyk Security Pages
- [pycodetags](https://security.snyk.io/package/pip/pycodetags)
- [pycodetags-issue-tracker](https://security.snyk.io/package/pip/pycodetags-issue-tracker) plugin
## Documentation
- [Readthedocs](https://pycodetags.readthedocs.io/en/latest/)
Raw data
{
"_id": null,
"home_page": null,
"name": "pycodetags",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "FIXME, TODO, code-tag, code-tags, codetag, codetags, pep-350, pep350, pycodetags",
"author": null,
"author_email": "Matthew Martin <matthewdeanmartin@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/7f/63/063aa384c5fbd64bf9862bdf88a35cc8ccf062d0316401a58d61a8006b93/pycodetags-0.6.0.tar.gz",
"platform": null,
"description": "# pycodetags\n\nYou've seen `# TODO:` comments? What if they could be used as an issue tracker?\n\nWhat if `# TODO:` style comments could serialize and deserialize records, turning comments into a database?\n\n[Live example](https://matthewdeanmartin.github.io/pycodetags/).\n\n\n[//]: # (What if you could also write comments as decorators that warn or stop you on the due date?)\n\n[//]: # ()\n[//]: # (Replace or complement your `# TODO:` comments with decorators similar to NotImplement, Deprecated or Warning)\n\n[//]: # (and get issue tracker features, too.)\n\nLightweight and keeps your issue tracker in your code.\n\nBackwards compatible with folk `# TODO:` comments, which can vary greatly in how people write them.\n\nCore library is for Data Tags, which are abstract and domain free. Plugs have domain-specific tags, e.g. Issue Tracking.\n\n## Installation\n\nFor generic code tags strictly in comments (DATA tags):\n\n`pipx install pycodetags`\n\nFor code tag decorators, objects, exceptions, context managers with run-time behavior:\n\n`pip install pycodetags`\n\nTo get a domain specific data tags (TODO tags), e.g. issue tracker or discussion, install with plugin\n\n`pip install pycodetags pycodetags-issue-tracker`\n\nRequires python 3.7+. 3.7 will probably work.\n\nThe only dependencies are `pluggy` and `ast-comments` and backports of python standard libraries to support old versions\nof python. For pure-comment style code tags, pipx install and nothing is installed with your application code.\n\n## Usage\n\n`pycodetags` can work with pre-existing comment based code tags, both the folk-schema style and the PEP-350 style.\n\nWays to track a TODO item\n\n- PEP-350 code tags, e.g. `# TODO: implement game <due=2025-06-01>`\n- Folk code tags, e.g. `# TODO(matth): example.com/ticktet=123 implement game`\n- ADVANCED: Add a function decorator, e.g. `@TODO(\"Work on this\")`\n\nWhile you work\n- View the issue-tracker-like single page website `pycodetas issues html`\n- Exceptions will be raised or logged when overdue\n\nAt build and release time\n\n- Fail build on overdue items (as opposed to failing build on the existence of any code tag, as pylint recommends)\n- Generate CHANGELOG.md using the keep-a-changelog format\n - `pycodetags issues changelog`\n- Generate DONE.txt, TODO.md, TODO.html files\n - `pycodetags issues todomd`\n - `pycodetags issues donefile`\n\n## Example\n\n```python\nfrom pycodetags_issue_tracker import TODO\n\n\n# Folk schema\n# TODO: Implement payments\n\n# PEP 350 Comment\n# TODO: Add a new feature for exporting. <assignee:matth priority=1 2025-06-15>\n\n# Attached to function\n@TODO(assignee=\"matth\", due=\"06/01/2025\", comment=\"Implement payment logic\")\ndef unfinished_feature():\n print(\"This should not run if overdue and assignee is Matthew.\")\n\n\n@TODO(status=\"Done\", tracker=\"https://ticketsystem/123\")\ndef finished_feature():\n print(\"This is a completed feature.\")\n\n\n# Wrapped around any block of code to show what the TODO is referring to\nwith TODO(comment=\"Needs Logging, not printing\", assignee=\"carol\", due=\"2025-07-01\"):\n print(100 / 3)\n\nif __name__ == \"__main__\":\n finished_feature() # won't throw\n unfinished_feature() # may throw if over due\n```\n\nTo generate reports:\n\n```text\n\u276f pycodetags\nusage: pycodetags [-h] [--config CONFIG] [--verbose] [--info] [--bug-trail] {data,plugin-info,issues} ...\n\nTODOs in source code as a first class construct, follows PEP350 (v0.3.0)\n\npositional arguments:\n {data,plugin-info,issues}\n Available commands\n data Generate code tag reports\n plugin-info Display information about loaded plugins\n issues Reports for TODOs and BUGs\n\noptions:\n -h, --help show this help message and exit\n --config CONFIG Path to config file, defaults to current folder pyproject.toml\n --verbose verbose level logging output\n --info info level logging output\n --bug-trail enable bug trail, local logging\n\nInstall pycodetags-issue-tracker plugin for TODO tags.\n```\n\n## How it works\nComments with some extra syntax are treated as a data serialization format.\n\n` # DATA: text <default-string default-date default-type data1:value data2:value custom1:value custom2:value`>\n\nCombined with a schema you get a code tag, or a discussion tag, e.g.\n\n`# BUG: Division by zero <MDM 2025-06-06 priority=3 storypoints=5>`\n\n`# QUESTION: Who thought this was a good idea? <MDM 2025-06-06 thread=1 snark=excessive>`\n\n```python\n# DATA: text\n# text line two\n```\n\n- The upper case tag in the `# DATA:` signals the start of a data tag.\n- The text continues until a `<>` block terminates or a non-comment line.\n- The `<>` block holds space separated key value pairs\n - The key is optional, values are optionally unquoted, single or double-quoted\n - Key value pairs follow, `key=value` or `key:value`\n - default fields are key-less fields identified by their type, e.g. `MDM`, `MDM,JQP`, or `2025-01-01`\n - data fields identified by a schema. PEP-350 is one schema. e.g. `assignee:MDM`, `assignee=MDM`\n - custom fields are data fields that are not expected by the schema. `program-increment:4`\n\nSee docs for handling edge cases.\n\n## Basic Workflow\n\n- Write code with TODOs, DONEs, and other code tags.\n- Run `pycodetags issues --validate` to ensure data quality is high enough to generate reports.\n- Run `pycodetags issues --format <format>` to generate reports.\n- Update tags as work is completed.\n\n## Configuration\n\nNo workflow or schema is one-size-fits all, so you will almost certainly want to do some configuration.\n\nThe expectation is that this config is used at development time, optionally on the build server and *not* when\ndeployed to production or an end users machine. If you are using only comment code tags, it is not an issue. There\nis a runtime cost or risk only when using strongly typed code tags.\n\nSee [documentation](https://pycodetags.readthedocs.io/en/latest/) for details.\n\n## Prior Art\n\nPEPs and Standard Library Prior Art\n\n- [PEP 350 - Code Tags](https://peps.python.org/pep-0350/) Rejected proposal, now implemented, mostly by `pycodetags`\n\n## Project Health\n\n| Metric | Status |\n|----------------|--------|\n| Coverage | [](https://codecov.io/gh/matthewdeanmartin/pycodetags) |\n| Docs | [](https://pycodetags.readthedocs.io/en/latest/) |\n| PyPI | [](https://pypi.org/project/pycodetags/) |\n| Downloads | [](https://pepy.tech/project/pycodetags) |\n| License | [](https://github.com/matthewdeanmartin/pycodetags/blob/main/LICENSE.md) |\n| Last Commit |  |\n\n## Libray info pages\n- [pycodetags](https://libraries.io/pypi/pycodetags)\n- [pycodetags-issue-tracker](https://libraries.io/pypi/pycodetags-issue-tracker) plugin\n\n## Snyk Security Pages\n\n- [pycodetags](https://security.snyk.io/package/pip/pycodetags)\n- [pycodetags-issue-tracker](https://security.snyk.io/package/pip/pycodetags-issue-tracker) plugin\n\n\n## Documentation\n\n- [Readthedocs](https://pycodetags.readthedocs.io/en/latest/)\n\n",
"bugtrack_url": null,
"license": null,
"summary": "TODOs in source code as a first class construct, follows PEP350",
"version": "0.6.0",
"project_urls": {
"Changelog": "https://github.com/matthewdeanmartin/pycodetags/blob/main/CHANGELOG.md",
"Documentation": "https://pycodetags.readthedocs.io/en/latest/",
"Repository": "https://github.com/matthewdeanmartin/pycodetags",
"homepage": "https://github.com/matthewdeanmartin/pycodetags",
"issues": "https://matthewdeanmartin.github.io/pycodetags/"
},
"split_keywords": [
"fixme",
" todo",
" code-tag",
" code-tags",
" codetag",
" codetags",
" pep-350",
" pep350",
" pycodetags"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "ae40c965b2d37b5578caa79def7d14694aec5fd80ded33b2f142ab5941d7f6d7",
"md5": "2e92224f0a9a1f12f886d77d06140ef2",
"sha256": "2f0b18f877ce2c479b983508a1cca03ad73150f4ccab5e30cb1e56cf98f7215f"
},
"downloads": -1,
"filename": "pycodetags-0.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "2e92224f0a9a1f12f886d77d06140ef2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 57640,
"upload_time": "2025-07-13T16:40:37",
"upload_time_iso_8601": "2025-07-13T16:40:37.386310Z",
"url": "https://files.pythonhosted.org/packages/ae/40/c965b2d37b5578caa79def7d14694aec5fd80ded33b2f142ab5941d7f6d7/pycodetags-0.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "7f63063aa384c5fbd64bf9862bdf88a35cc8ccf062d0316401a58d61a8006b93",
"md5": "14c10669eb6252b5354bc046636a8d55",
"sha256": "540453e266a6b5ccfc2bcdabc2ec4deba7087e3b5dac9b0539db03a0f0cf82fb"
},
"downloads": -1,
"filename": "pycodetags-0.6.0.tar.gz",
"has_sig": false,
"md5_digest": "14c10669eb6252b5354bc046636a8d55",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 70751,
"upload_time": "2025-07-13T16:40:39",
"upload_time_iso_8601": "2025-07-13T16:40:39.208379Z",
"url": "https://files.pythonhosted.org/packages/7f/63/063aa384c5fbd64bf9862bdf88a35cc8ccf062d0316401a58d61a8006b93/pycodetags-0.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-13 16:40:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "matthewdeanmartin",
"github_project": "pycodetags",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "pycodetags"
}