Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ Below is the help output::
-i, --in-place make changes to files instead of printing diffs
-c, --check only check and report incorrectly formatted files
-r, --recursive drill down directories recursively
-e, --exclude exclude directories and files by names

--wrap-summaries length
wrap long summary lines at this length; set to 0 to
disable wrapping (default: 79)
Expand Down
25 changes: 20 additions & 5 deletions docformatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import sys
import textwrap
import tokenize
from distutils.sysconfig import get_python_lib
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you try with standard sysconfig module instead of distutils?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, can do. Thx for the input


import untokenize

Expand Down Expand Up @@ -609,6 +610,8 @@ def _main(argv, standard_out, standard_error, standard_in):
'files')
parser.add_argument('-r', '--recursive', action='store_true',
help='drill down directories recursively')
parser.add_argument('-e', '--exclude', nargs="*",
help='exclude directories and files by names')
parser.add_argument('--wrap-summaries', default=79, type=int,
metavar='length',
help='wrap long summary lines at this length; '
Expand Down Expand Up @@ -692,25 +695,37 @@ def _get_encoding():
return locale.getpreferredencoding() or sys.getdefaultencoding()


def find_py_files(sources, recursive):
def find_py_files(sources, recursive, exclude=None):
"""Find Python source files.

Parameters
- sources: iterable with paths as strings.
- recursive: drill down directories if True.
- exclude: string based on which directories and files are excluded.

Return: yields paths to found files.
"""
def not_hidden(name):
"""Return True if file 'name' isn't .hidden."""
return not name.startswith('.')

def is_excluded(name, exclude):
"""Return True if file 'name' is excluded."""
if not exclude:
return False
for e in exclude:
if re.search(re.escape(str(e)), name, re.IGNORECASE):
return True
return False

for name in sorted(sources):
if recursive and os.path.isdir(name):
for root, dirs, children in os.walk(unicode(name)):
dirs[:] = sorted(filter(not_hidden, dirs))
for filename in sorted(filter(not_hidden, children)):
if filename.endswith('.py'):
dirs[:] = [d for d in dirs if not_hidden(d) and not is_excluded(d, [get_python_lib()])]
dirs[:] = sorted([d for d in dirs if not is_excluded(d, exclude)])
files = sorted([f for f in children if not_hidden(f) and not is_excluded(f, exclude)])
for filename in files:
if filename.endswith('.py') and not is_excluded(root, exclude):
yield os.path.join(root, filename)
else:
yield name
Expand All @@ -722,7 +737,7 @@ def _format_files(args, standard_out, standard_error):
Return: one of the FormatResult codes.
"""
outcomes = collections.Counter()
for filename in find_py_files(set(args.files), args.recursive):
for filename in find_py_files(set(args.files), args.recursive, args.exclude):
try:
result = format_file(filename, args=args,
standard_out=standard_out)
Expand Down
38 changes: 38 additions & 0 deletions test_docformatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import sys
import tempfile
import unittest
from unittest.mock import patch

import docformatter

Expand Down Expand Up @@ -1182,6 +1183,43 @@ def test_format_docstring_make_summary_multi_line(self):
"""This one-line docstring will be multi-line"""\
''', make_summary_multi_line=True))

def test_exclude(self):
sources = {"/root"}
patch_data = [
("/root", ['folder_one', 'folder_two'], []),
("/root/folder_one", ['folder_three'], ["one.py"]),
("/root/folder_one/folder_three", [], ["three.py"]),
("/root/folder_two", [], ["two.py"]),
]
with patch("os.walk", return_value=patch_data), patch("os.path.isdir", return_value=True):
test_exclude_one = list(docformatter.find_py_files(sources, True, ["folder_one"]))
self.assertEqual(test_exclude_one, ['/root/folder_two/two.py'])
test_exclude_two = list(docformatter.find_py_files(sources, True, ["folder_two"]))
self.assertEqual(test_exclude_two, ['/root/folder_one/one.py', '/root/folder_one/folder_three/three.py'])
test_exclude_three = list(docformatter.find_py_files(sources, True, ["folder_three"]))
self.assertEqual(test_exclude_three, ['/root/folder_one/one.py', '/root/folder_two/two.py'])
test_exclude_py = list(docformatter.find_py_files(sources, True, ".py"))
self.assertFalse(test_exclude_py)
test_exclude_two_and_three = list(docformatter.find_py_files(sources, True, ["folder_two", "folder_three"]))
self.assertEqual(test_exclude_two_and_three, ['/root/folder_one/one.py'])
test_exclude_files = list(docformatter.find_py_files(sources, True, ["one.py", "two.py"]))
self.assertEqual(test_exclude_files, ['/root/folder_one/folder_three/three.py'])

def test_exclude_nothing(self):
sources = {"/root"}
patch_data = [
("/root", ['folder_one', 'folder_two'], []),
("/root/folder_one", ['folder_three'], ["one.py"]),
("/root/folder_one/folder_three", [], ["three.py"]),
("/root/folder_two", [], ["two.py"]),
]
with patch("os.walk", return_value=patch_data), patch("os.path.isdir", return_value=True):
test_exclude_nothing = list(docformatter.find_py_files(sources, True, []))
self.assertEqual(test_exclude_nothing, ['/root/folder_one/one.py', '/root/folder_one/folder_three/three.py',
'/root/folder_two/two.py'])
test_exclude_nothing = list(docformatter.find_py_files(sources, True))
self.assertEqual(test_exclude_nothing, ['/root/folder_one/one.py', '/root/folder_one/folder_three/three.py',
'/root/folder_two/two.py'])

class TestSystem(unittest.TestCase):

Expand Down