Skip to content

Commit

Permalink
Merge pull request #41 from miki725/configs
Browse files Browse the repository at this point in the history
Configs
  • Loading branch information
miki725 committed Oct 6, 2017
2 parents 625b2cc + 6556b05 commit 2e17d19
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 55 deletions.
5 changes: 5 additions & 0 deletions HISTORY.rst
Expand Up @@ -3,6 +3,11 @@
History
-------

0.6.1 (2017-10-06)
~~~~~~~~~~~~~~~~~~

* Fixed sub-configrations. They are searched when organizing individual files now.

0.6.0 (2017-10-06)
~~~~~~~~~~~~~~~~~~

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.0'
__version__ = '0.6.1'
__description__ = (
'Utility for organizing Python imports using PEP8 or custom rules'
)
90 changes: 66 additions & 24 deletions importanize/__main__.py
Expand Up @@ -20,7 +20,7 @@
get_text_artifacts,
parse_statements,
)
from .utils import force_text, read
from .utils import force_text


LOGGING_FORMAT = '%(message)s'
Expand Down Expand Up @@ -62,19 +62,56 @@
log = logging.getLogger(__name__)


def find_config():
path = pathlib.Path.cwd()
default_config = None
@six.python_2_unicode_compatible
class Config(dict):
def __init__(self, *args, **kwargs):
self.path = kwargs.pop('path', None)
super(Config, self).__init__(*args, **kwargs)

while path != pathlib.Path(path.root):
config_path = path / IMPORTANIZE_CONFIG
if config_path.exists():
default_config = six.text_type(config_path)
break
else:
path = path.parent
@classmethod
def default(cls):
return cls(
PEP8_CONFIG,
)

@classmethod
def from_path(cls, path):
if not path:
return cls.default()
path = pathlib.Path(path)

try:
return cls(
json.loads(path.read_text('utf-8')),
path=path,
)
except ValueError:
log.exception(
'Invalid configuration @ {}. Defaulting to pep8.'
''.format(path)
)
return cls.default()

@classmethod
def find(cls, cwd=pathlib.Path.cwd(), root=None):
path = cwd

while path != pathlib.Path(root or cwd.root):
config_path = path / IMPORTANIZE_CONFIG
if config_path.exists():
return Config.from_path(config_path)
else:
path = path.parent

return cls.default()

def __str__(self):
return six.text_type(self.path or '<default pep8>')

def __bool__(self):
return bool(self.path)

return default_config
__nonzero__ = __bool__


parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -120,6 +157,13 @@ def find_config():
'before each file. '
'Useful to leave when multiple files are importanized.'
)
parser.add_argument(
'--no-subconfig',
action='store_false',
default=True,
dest='subconfig',
help='If provided, sub-configurations will not be used.'
)
parser.add_argument(
'--ci',
action='store_true',
Expand Down Expand Up @@ -247,6 +291,12 @@ def run(source, config, args, path=None):
return organized

elif source.is_file():
if args.subconfig:
config = Config.find(
cwd=source.parent,
root=getattr(config.path, 'parent', None)
) or config

if config.get('exclude'):
norm = os.path.normpath(os.path.abspath(six.text_type(source)))
if any(map(lambda i: fnmatch(norm, i),
Expand All @@ -258,13 +308,6 @@ def run(source, config, args, path=None):
return run(text, config, args, source)

elif source.is_dir():
config_path = source / IMPORTANIZE_CONFIG
if config_path.exists():
try:
config = json.loads(config_path.read_text('utf-8'))
except ValueError:
log.error('Invalid sub-configuration {}'.format(config_path))

if config.get('exclude'):
norm = os.path.normpath(os.path.abspath(six.text_type(source)))
if any(map(lambda i: fnmatch(norm, i),
Expand Down Expand Up @@ -295,14 +338,15 @@ def is_piped():
def main(args=None):
args = args if args is not None else sys.argv[1:]
args = parser.parse_args(args=args)

# adjust logging level
(logging.getLogger('')
.setLevel(VERBOSITY_MAPPING.get(args.verbose, 0)))

log.debug('Running importanize with {}'.format(args))

config_path = getattr(args.config, 'name', '') or find_config()
config = Config.from_path(
getattr(args.config, 'name', '')
) or Config.find()

if args.version:
msg = (
Expand All @@ -318,12 +362,10 @@ def main(args=None):
description=__description__,
version=__version__,
python=sys.executable,
config=config_path or '<default pep8>',
config=config,
))
return 0

config = json.loads(read(config_path)) if config_path else PEP8_CONFIG

to_importanize = [pathlib.Path(i) for i in (args.path or ['.'])]

if is_piped() and not args.path:
Expand Down
78 changes: 48 additions & 30 deletions tests/test_main.py
Expand Up @@ -14,7 +14,7 @@
IMPORTANIZE_CONFIG,
PEP8_CONFIG,
CIFailure,
find_config,
Config,
main,
run,
run_importanize_on_text,
Expand Down Expand Up @@ -46,7 +46,8 @@ def test_run_importanize_on_text_grouped(self):
self.input_text,
CONFIG,
mock.Mock(formatter='grouped',
ci=False),
ci=False,
subconfig=False),
)

self.assertEqual(actual, self.output_grouped)
Expand All @@ -56,7 +57,8 @@ def test_run_importanize_on_text_inline_grouped(self):
self.input_text,
CONFIG,
mock.Mock(formatter='inline-grouped',
ci=False),
ci=False,
subconfig=False),
)

self.assertEqual(actual, self.output_inline_grouped)
Expand All @@ -67,15 +69,17 @@ def test_run_importanize_on_text_ci_failed(self):
self.input_text,
CONFIG,
mock.Mock(formatter='grouped',
ci=True),
ci=True,
subconfig=False),
)

def test_run_importanize_on_text_ci_passed(self):
actual = run_importanize_on_text(
self.output_grouped,
CONFIG,
mock.Mock(formatter='grouped',
ci=True),
ci=True,
subconfig=False),
)

self.assertEqual(actual, self.output_grouped)
Expand All @@ -87,7 +91,8 @@ def test_run_text_to_file_organized(self, mock_write_text):
CONFIG,
mock.Mock(formatter='grouped',
ci=False,
print=False),
print=False,
subconfig=False),
Path(__file__),
)

Expand All @@ -101,7 +106,8 @@ def test_run_text_to_file_nothing_to_do(self, mock_write_text):
CONFIG,
mock.Mock(formatter='grouped',
ci=False,
print=False),
print=False,
subconfig=False),
Path(__file__),
)

Expand All @@ -116,7 +122,8 @@ def test_run_text_print(self, mock_print):
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=True),
header=True,
subconfig=False),
Path('foo'),
)

Expand All @@ -136,7 +143,8 @@ def test_run_text_print_no_file(self, mock_print):
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=True),
header=True,
subconfig=False),
)

self.assertEqual(actual, self.output_grouped)
Expand All @@ -152,7 +160,8 @@ def test_run_text_print_no_header(self, mock_print):
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=False),
Path('foo'),
)

Expand All @@ -168,11 +177,12 @@ def test_run_file_skipped(self, mock_print):

actual = run(
self.test_data / 'input.py',
config,
Config(config),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=False),
)

self.assertIsNone(actual)
Expand All @@ -182,11 +192,12 @@ def test_run_file_skipped(self, mock_print):
def test_run_file(self, mock_print):
actual = run(
self.test_data / 'input.py',
CONFIG,
Config(CONFIG),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=False),
)

self.assertEqual(actual, self.output_grouped)
Expand All @@ -196,11 +207,12 @@ def test_run_file(self, mock_print):
def test_run_dir(self, mock_print):
actual = run(
self.test_data,
CONFIG,
Config(CONFIG),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=False),
)

self.assertIsNone(actual)
Expand All @@ -216,11 +228,12 @@ def test_run_dir_subconfig_invalid(self, mock_print):
try:
actual = run(
self.test_data,
CONFIG,
Config(CONFIG),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=True),
)

self.assertIsNone(actual)
Expand All @@ -242,11 +255,12 @@ def test_run_dir_subconfig_valid(self, mock_print):
try:
actual = run(
self.test_data,
CONFIG,
Config(CONFIG),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=True),
)

self.assertIsNone(actual)
Expand All @@ -264,11 +278,12 @@ def test_run_dir_skipped(self, mock_print):

actual = run(
self.test_data,
config,
Config(config),
mock.Mock(formatter='grouped',
ci=False,
print=True,
header=False),
header=False,
subconfig=False),
)

self.assertIsNone(actual)
Expand All @@ -279,23 +294,26 @@ def test_run_dir_ci(self, mock_print):
with self.assertRaises(CIFailure):
run(
self.test_data,
CONFIG,
Config(CONFIG),
mock.Mock(formatter='grouped',
ci=True,
print=True,
header=False),
header=False,
subconfig=False),
)

@mock.patch.object(Path, 'cwd')
def test_find_config(self, mock_cwd):
mock_cwd.return_value = Path(__file__)

config = find_config()
def test_find_config(self):
config = Config.find(Path(__file__))

expected_config = Path(__file__).parent.parent.joinpath(
IMPORTANIZE_CONFIG
)
self.assertEqual(config, six.text_type(expected_config.resolve()))
self.assertEqual(config.path, expected_config)

def test_find_config_nonfound(self):
config = Config.find(Path(Path(__file__).root))

self.assertIsNone(config.path)

@mock.patch(TESTING_MODULE + '.print', create=True)
def test_main_version(self, mock_print):
Expand Down

0 comments on commit 2e17d19

Please sign in to comment.