Skip to content

Commit

Permalink
Merge pull request #50 from miki725/list
Browse files Browse the repository at this point in the history
--list
  • Loading branch information
miki725 committed Jun 7, 2018
2 parents 123fdee + 6999c9e commit 754814e
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 96 deletions.
6 changes: 6 additions & 0 deletions HISTORY.rst
Expand Up @@ -3,6 +3,12 @@
History
-------

0.7.0 (2018-06-06)
~~~~~~~~~~~~~~~~~~

* Fixed removing first line in files without imports.
* Added ``--list`` option to list all found imports grouped by same packages as in config.

0.6.4 (2018-05-29)
~~~~~~~~~~~~~~~~~~

Expand Down
2 changes: 1 addition & 1 deletion importanize/__init__.py
Expand Up @@ -4,7 +4,7 @@

__author__ = 'Miroslav Shubernetskiy'
__email__ = 'miroslav@miki725.com'
__version__ = '0.6.4'
__version__ = '0.7.0'
__description__ = (
'Utility for organizing Python imports using PEP8 or custom rules'
)
75 changes: 53 additions & 22 deletions importanize/__main__.py
Expand Up @@ -7,6 +7,7 @@
import os
import sys
from fnmatch import fnmatch
from itertools import chain
from stat import S_ISFIFO

import pathlib2 as pathlib
Expand Down Expand Up @@ -97,7 +98,7 @@ def find(cls, cwd=None, root=None):
cwd = cwd or pathlib.Path.cwd()
path = cwd = cwd.resolve()

while path != pathlib.Path(root or cwd.root):
while path.resolve() != pathlib.Path(root or cwd.root).resolve():
config_path = path / IMPORTANIZE_CONFIG
if config_path.exists():
return Config.from_path(config_path)
Expand Down Expand Up @@ -177,6 +178,12 @@ def __bool__(self):
help='When used CI mode will check if file contains expected '
'imports as per importanize configuration.'
)
parser.add_argument(
'--list',
action='store_true',
default=False,
help='List all dependencies found in all parsed files'
)
parser.add_argument(
'--version',
action='store_true',
Expand Down Expand Up @@ -215,20 +222,14 @@ def run_importanize_on_text(text, config, args):
for i in imports:
groups.add_statement_to_group(i)

line_numbers = groups.all_line_numbers()
first_import_line_number = min(line_numbers) if line_numbers else 0

for i in config.get('add_imports', []):
for j in parse_statements([([i], [first_import_line_number])]):
groups.add_statement_to_group(j)
if args.list:
return groups

formatted_imports = groups.formatted(
formatter=formatter,
length=args.length or config.get('length') or DEFAULT_LENGTH,
)
line_numbers = groups.all_line_numbers()
first_import_line_number = min(line_numbers) if line_numbers else None

lines = text.splitlines()
for line_number in sorted(groups.all_line_numbers(), reverse=True):
for line_number in sorted(set(groups.all_line_numbers()), reverse=True):
if lines:
lines.pop(line_number)

Expand All @@ -239,13 +240,22 @@ def run_importanize_on_text(text, config, args):
else:
i = None

for i in config.get('add_imports', []):
for j in parse_statements([([i], [first_import_line_number or 0])]):
groups.add_statement_to_group(j)

formatted_imports = groups.formatted(
formatter=formatter,
length=args.length or config.get('length') or DEFAULT_LENGTH,
)

lines = (
lines[:first_import_line_number] +
lines[:first_import_line_number or 0] +
formatted_imports.splitlines() +
([''] * config.get('after_imports_new_lines', 2)
if lines[first_import_line_number:] and formatted_imports
if lines[first_import_line_number or 0:] and formatted_imports
else []) +
lines[first_import_line_number:] +
lines[first_import_line_number or 0:] +
['']
)

Expand Down Expand Up @@ -275,6 +285,10 @@ def run(source, config, args, path=None):
raise

else:
if args.list:
yield organized
return

if args.print and args.header and path:
print('=' * len(six.text_type(path)))
print(six.text_type(path))
Expand All @@ -298,7 +312,7 @@ def run(source, config, args, path=None):
msg += ' {}'.format(path)
log.info(msg)

return organized
yield organized

elif source.is_file():
if args.subconfig:
Expand All @@ -311,18 +325,19 @@ def run(source, config, args, path=None):
norm = os.path.normpath(os.path.abspath(six.text_type(source)))
if any(map(lambda i: fnmatch(norm, i),
config.get('exclude'))):
log.info('Skipping {}'.format(source))
log.info('Skipping {} as per {}'.format(source, config))
return

text = source.read_text('utf-8')
return run(text, config, args, source)
for i in run(text, config, args, source):
yield i

elif source.is_dir():
if config.get('exclude'):
norm = os.path.normpath(os.path.abspath(six.text_type(source)))
if any(map(lambda i: fnmatch(norm, i),
config.get('exclude'))):
log.info('Skipping {}'.format(source))
log.info('Skipping {} as per {}'.format(source, config))
return

files = (
Expand All @@ -333,7 +348,8 @@ def run(source, config, args, path=None):
all_successes = True
for f in files:
try:
run(f, config, args, f)
for i in run(f, config, args, f):
yield i
except CIFailure:
all_successes = False

Expand Down Expand Up @@ -383,21 +399,36 @@ def main(args=None):
args.print = True
args.header = False

if args.ci:
if args.ci or args.list:
args.print = False
args.header = False

all_successes = True
all_groups = []

for p in to_importanize:
try:
run(p, config, args)
all_groups += [i for i in run(p, config, args)]
except CIFailure:
all_successes = False
except Exception:
log.exception('Error running importanize')
return 1

if args.list:
groups = ImportGroups()
for c in config['groups']:
groups.add_group(c)
statements = chain(*(i.statements for i in chain(*all_groups)))
for s in statements:
groups.add_statement_to_group(s)
for g in groups:
print(g.config['type'])
print('-' * len(g.config['type']))
for s in g.unique_statements:
print(six.text_type(s))
print()

return int(not all_successes)


Expand Down
28 changes: 16 additions & 12 deletions importanize/groups.py
Expand Up @@ -16,7 +16,7 @@ class BaseImportGroup(object):
def __init__(self, config=None, **kwargs):
self.config = config or {}

self.statements = []
self.statements = kwargs.get('statements', [])
self.file_artifacts = kwargs.get('file_artifacts', {})

@property
Expand Down Expand Up @@ -133,16 +133,23 @@ def should_add_statement(self, statement):
))


def sort_groups(groups):
return sorted(
groups,
key=lambda i: list(GROUP_MAPPING.values()).index(type(i))
)


@six.python_2_unicode_compatible
class ImportGroups(object):
def __init__(self, **kwargs):
self.groups = []
class ImportGroups(list):
def __init__(self, *args, **kwargs):
super(ImportGroups, self).__init__(*args)
self.file_artifacts = kwargs.get('file_artifacts', {})

def all_line_numbers(self):
return sorted(list(set(list(
itertools.chain(*map(operator.methodcaller('all_line_numbers'),
self.groups))
self))
))))

def add_group(self, config):
Expand All @@ -155,13 +162,10 @@ def add_group(self, config):
msg = ('"{}" is not supported import group'.format(config['type']))
raise ValueError(msg)

self.groups.append(GROUP_MAPPING[config['type']](config))
self.append(GROUP_MAPPING[config['type']](config))

def add_statement_to_group(self, statement):
groups_by_priority = sorted(
self.groups,
key=lambda i: list(GROUP_MAPPING.values()).index(type(i))
)
groups_by_priority = sort_groups(self)

added = False

Expand All @@ -182,7 +186,7 @@ def as_string(self):
sep = self.file_artifacts.get('sep', '\n') * 2
return sep.join(filter(
None, map(operator.methodcaller('as_string'),
self.groups)
self)
))

def formatted(self, formatter=DEFAULT_FORMATTER, length=DEFAULT_LENGTH):
Expand All @@ -191,7 +195,7 @@ def formatted(self, formatter=DEFAULT_FORMATTER, length=DEFAULT_LENGTH):
None, map(operator.methodcaller('formatted',
formatter=formatter,
length=length),
self.groups)
self)
))

def __str__(self):
Expand Down
7 changes: 7 additions & 0 deletions tests/test_data/input_few_imports.py
@@ -0,0 +1,7 @@
from __future__ import unicode_literals
from .module import foo, bar
from a import b
import flake8 as lint # in site-package
from a.b import d
import z
import datetime as mydatetime
1 change: 1 addition & 0 deletions tests/test_data/input_no_imports.py
@@ -0,0 +1 @@
foo = 'bar'
4 changes: 4 additions & 0 deletions tests/test_data/output_no_imports.py
@@ -0,0 +1,4 @@
from __future__ import absolute_import, print_function, unicode_literals


foo = 'bar'
28 changes: 14 additions & 14 deletions tests/test_groups.py
Expand Up @@ -238,7 +238,7 @@ def test_should_add_statement(self):
class TestImportGroups(unittest.TestCase):
def test_init(self):
groups = ImportGroups()
self.assertListEqual(groups.groups, [])
self.assertListEqual(groups, [])

def test_all_line_numbers(self):
groups = ImportGroups()
Expand All @@ -248,12 +248,12 @@ def test_all_line_numbers(self):
g = BaseImportGroup()
g.statements = [mock.MagicMock(line_numbers=[2, 7],
spec=ImportStatement)]
groups.groups.append(g)
groups.append(g)

g = BaseImportGroup()
g.statements = [mock.MagicMock(line_numbers=[1, 2],
spec=ImportStatement)]
groups.groups.append(g)
groups.append(g)

self.assertListEqual(groups.all_line_numbers(), [1, 2, 7])

Expand All @@ -268,14 +268,14 @@ def test_add_group(self):

groups.add_group({'type': 'stdlib'})

self.assertEqual(len(groups.groups), 1)
self.assertEqual(groups.groups[0].__class__, StdLibGroup)
self.assertEqual(len(groups), 1)
self.assertEqual(groups[0].__class__, StdLibGroup)

def test_add_statement_to_group_one(self):
groups = ImportGroups()
groups.groups = [
groups.extend([
LocalGroup()
]
])

with self.assertRaises(ValueError):
groups.add_statement_to_group(
Expand All @@ -287,27 +287,27 @@ def test_add_statement_to_group_one(self):
)

self.assertListEqual(
groups.groups[0].statements,
groups[0].statements,
[ImportStatement([], '.a')]
)

def test_add_statement_to_group_priority(self):
groups = ImportGroups()
groups.groups = [
groups.extend([
RemainderGroup(),
LocalGroup(),
]
])

groups.add_statement_to_group(
ImportStatement([], '.a')
)

self.assertListEqual(
groups.groups[0].statements,
groups[0].statements,
[]
)
self.assertListEqual(
groups.groups[1].statements,
groups[1].statements,
[ImportStatement([], '.a')]
)

Expand All @@ -321,10 +321,10 @@ def test_formatted_with_artifacts(self):
artifacts = {'sep': '\r\n'}

groups = ImportGroups(file_artifacts=artifacts)
groups.groups = [
groups.extend([
RemainderGroup(file_artifacts=artifacts),
LocalGroup(file_artifacts=artifacts),
]
])

groups.add_statement_to_group(
ImportStatement([], '.a', file_artifacts=artifacts)
Expand Down

0 comments on commit 754814e

Please sign in to comment.