Skip to content

Instantly share code, notes, and snippets.

@jzohrab
Last active April 4, 2021 20:25
Show Gist options
  • Select an option

  • Save jzohrab/7d655a8e506da09955fe695da3fe54f6 to your computer and use it in GitHub Desktop.

Select an option

Save jzohrab/7d655a8e506da09955fe695da3fe54f6 to your computer and use it in GitHub Desktop.
Python list TODOs
# Helper method to dump project TODOs to stdout.
#
# Script can be stored anywhere, but should be run from the project
# root dir:
# python tools/list_todos.py
#
# Sample output:
#
# Current TODOs by category:
#
# base (code fixes that will require some rearchitecting)
#
# ./path/to/file.py (medium): rest of comment
#
# fix (code fixes)
#
# ./other/file.py (high): add config validation
# ...
import os, fnmatch, re
# Types of todos:
# docs = documentation
# base = fundamental project changes/investigations
# nice = nice-to-have
TODO_TYPES = {
'base': 'code fixes that will require some rearchitecting',
'fix': 'code fixes',
'docs': 'documentation',
'nice': 'nice-to-haves'
}
PRIORITIES = { 'high': 'high',
'med': 'medium',
'low': 'low' }
# Config
ignore_dirs = ['./venv', './.git', './docs/_build', './tools']
ignore_file_exts = ['.pyc']
ignore_files = ['./docs/conf.py', './README.md']
def find_files(directory, pattern, ignore_dirs, ignore_file_exts):
"Generator: find files, prune search tree during search."
for root, subdirs, files in os.walk(directory):
prune_subdirs = []
for d in subdirs:
if os.path.join(root, d) in ignore_dirs:
prune_subdirs.append(d)
for d in prune_subdirs:
subdirs.remove(d)
for basename in files:
filename, ext = os.path.splitext(basename)
if ext not in ignore_file_exts and fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename
def make_todo(filename, line):
"""Breaks a line up into a hash.
expected TODO format: 'TODO type/priority: rest of line'"""
header, rest = line.split(':')
p = 'medium' # default
for s in PRIORITIES:
if re.search(s, header, re.IGNORECASE):
p = PRIORITIES[s]
break
todo_type = ''
for s in TODO_TYPES:
if re.search(s, header, re.IGNORECASE):
todo_type = s
break
hsh = {
'filename': filename,
'line': line.lstrip(' '),
'priority': p,
'type': todo_type,
'rest': rest
}
return hsh
def collect_todos(filename):
with open(filename, 'r') as f:
data = f.read()
return [make_todo(filename, lin) for lin in data.split('\n') if re.search('todo', lin, re.IGNORECASE)]
def print_todos(all_todos):
"""Prints todos collected by make_todo."""
def print_section(todo_type, todos):
if len(todos) == 0:
return
desc = TODO_TYPES.get(todo_type, "uncategorized")
print '\n{0} ({1})\n'.format(todo_type, desc)
for t in todos:
print ' {0} ({1}): {2}'.format(t['filename'], t['priority'], t['rest'])
for tt in ('base', 'fix', 'docs', 'nice'):
todos = [t for t in all_todos if t['type'] == tt]
print_section(tt, todos)
all_todos = [t for t in all_todos if t not in todos]
print_section('remaining', all_todos)
# Output.
print "\nCurrent TODOs by category:"
todos = []
for filename in find_files('.', '*.*', ignore_dirs, ignore_file_exts):
if filename not in ignore_files:
todos.extend(collect_todos(filename))
print_todos(todos)
print
@avatar-lavventura
Copy link
Copy Markdown

I am having following error:

Current TODOs by category:
Traceback (most recent call last):
  File "list_todos.py", line 113, in <module>
    todos.extend(collect_todos(filename))
  File "list_todos.py", line 87, in collect_todos
    return [make_todo(filename, lin) for lin in data.split('\n') if re.search('todo', lin, re.IGNORECASE)]
  File "list_todos.py", line 62, in make_todo
    header, rest = line.split(':')
ValueError: need more than 1 value to unpack

@jzohrab
Copy link
Copy Markdown
Author

jzohrab commented Jan 22, 2021

Hi @avatar-lavventura -- not sure offhand, but if you have a file that has "todo" but no ":", it may cause this error. Ref this stackoverflow. Print the line and see what it has, and maybe add a check to ensure the line contains ":". Cheers!

@avatar-lavventura
Copy link
Copy Markdown

avatar-lavventura commented Jan 23, 2021

Should I run the code using python2.7 or python3? // All my Python files have # TODO: pattern , it forces this error to be generated

@jzohrab
Copy link
Copy Markdown
Author

jzohrab commented Apr 3, 2021

Per the comment: expected TODO format: 'TODO type/priority: rest of line'

@avatar-lavventura
Copy link
Copy Markdown

Can't is list them without any type/priority option?

example line:

# print("hello world")  # TODO: uncomment

@jzohrab
Copy link
Copy Markdown
Author

jzohrab commented Apr 4, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment