<commit_before>#!/usr/bin/env python

# Copyright 2017 Stanford University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from __future__ import print_function
import argparse, codecs, glob, itertools, json, multiprocessing, os, optparse, re, shutil, subprocess, sys, tempfile, traceback
from collections import OrderedDict
import regent

_version = sys.version_info.major

if _version == 2: # Python 2.x:
    def _glob(path):
        def visit(result, dirname, filenames):
            for filename in filenames:
                result.append(os.path.join(dirname, filename))
        result = []
        os.path.walk(path, visit, result)
        return result
elif _version == 3: # Python 3.x:
    def _glob(path):
        return [os.path.join(dirname, filename)
                for dirname, _, filenames in os.walk(path)
                for filename in filenames]
else:
    raise Exception('Incompatible Python version')

class TestFailure(Exception):
    def __init__(self, command, output):
        Exception.__init__(self, command, output)
        self.command = command
        self.output = output

def run(filename, debug, verbose, flags, env):
    args = ((['-mg'] if debug else []) +
            [os.path.basename(filename)] + flags +
            ([] if verbose else ['-level', '5']))
    if verbose: print('Running', ' '.join(args))
    proc = regent.regent(
        args,
        stdout=None if verbose else subprocess.PIPE,
        stderr=None if verbose else subprocess.STDOUT,
        env=env,
        cwd=os.path.dirname(os.path.abspath(filename)))
    output, _ = proc.communicate()
    retcode = proc.wait()
    if retcode != 0:
        raise TestFailure(' '.join(args), output.decode('utf-8') if output is not None else None)

def run_spy(logfiles, verbose):
    cmd = ['pypy', os.path.join(regent.root_dir(), 'tools', 'legion_spy.py'),
           '--logical',
           '--physical',
           '--cycle',
           # '--sanity', # FIXME: This breaks on several test cases.
           '--leaks',
           # '--geometry', # FIXME: This is *very* slow.
           '--assert-error',
           '--assert-warning'] + logfiles
    if verbose: print('Running', ' '.join(cmd))
    proc = subprocess.Popen(
        cmd,
        stdout=None if verbose else subprocess.PIPE,
        stderr=None if verbose else subprocess.STDOUT)
    output, _ = proc.communicate()
    retcode = proc.wait()
    if retcode != 0:
        raise TestFailure(' '.join(cmd), output.decode('utf-8') if output is not None else None)

_re_label = r'^[ \t\r]*--[ \t]+{label}:[ \t\r]*$\n((^[ \t\r]*--.*$\n)+)'
def find_labeled_text(filename, label):
    re_label = re.compile(_re_label.format(label=label), re.MULTILINE)
    with codecs.open(filename, 'r', encoding='utf-8') as f:
        program_text = f.read()
    match = re.search(re_label, program_text)
    if match is None:
        return None
    match_lines = match.group(1).strip().split('\n')
    match_text = '\n'.join([line.strip()[2:].strip() for line in match_lines])
    return match_text

def find_labeled_flags(filename, prefix):
    flags = [[]]
    flags_text = find_labeled_text(filename, prefix)
    if flags_text is not None:
        flags = json.loads(flags_text)
        assert isinstance(flags, list), "%s declaration must be a json-formatted nested list" % prefix
        for flag in flags:
            assert isinstance(flag, list), "%s declaration must be a json-formatted nested list" % prefix
    return flags

def test_compile_fail(filename, debug, verbose, flags, env):
    expected_failure = find_labeled_text(filename, 'fails-with')
    if expected_failure is None:
        raise Exception('No fails-with declaration in compile_fail test')

    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            run(filename, debug, False, flags + params, env)
    except TestFailure as e:
        failure = e.output
        lines = set(line.strip() for line in failure.strip().split('\n')
                    if len(line.strip()) > 0)
        expected_lines = expected_failure.split('\n')
        for expected_line in expected_lines:
            if expected_line not in lines:
                raise Exception('Command failed:\n%s\n\nExpected failure:\n%s\n\nInstead got:\n%s' % (e.command, expected_failure, failure))
    else:
        raise Exception('Expected failure, but test passed')

def test_run_pass(filename, debug, verbose, flags, env):
    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            run(filename, debug, verbose, flags + params, env)
    except TestFailure as e:
        raise Exception('Command failed:\n%s\n\nOutput:\n%s' % (e.command, e.output))

def test_spy(filename, debug, verbose, flags, env):
    spy_dir = tempfile.mkdtemp(dir=os.path.dirname(os.path.abspath(filename)))
    spy_log = os.path.join(spy_dir, 'spy_%.log')
    spy_flags = ['-level', 'legion_spy=2', '-logfile', spy_log]

    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            run(filename, debug, verbose, flags + params + spy_flags, env)
            spy_logs = glob.glob(os.path.join(spy_dir, 'spy_*.log'))
            assert len(spy_logs) > 0
            run_spy(spy_logs, verbose)
    except TestFailure as e:
        raise Exception('Command failed:\n%s\n\nOutput:\n%s' % (e.command, e.output))
    finally:
        shutil.rmtree(spy_dir)

red = "\033[1;31m"
green = "\033[1;32m"
clear = "\033[0m"

PASS = 'pass'
FAIL = 'fail'
INTERRUPT = 'interrupt'

def test_runner(test_name, test_closure, debug, verbose, filename):
    test_fn, test_args = test_closure
    saved_temps = []
    try:
        test_fn(filename, debug, verbose, *test_args)
    except KeyboardInterrupt:
        return test_name, filename, [], INTERRUPT, None
    # except driver.CompilerException as e:
    #     if verbose:
    #         return test_name, filename, e.saved_temps, FAIL, ''.join(traceback.format_exception(*sys.exc_info()))
    #     return test_name, filename, e.saved_temps, FAIL, None
    except Exception as e:
        if verbose:
            return test_name, filename, [], FAIL, ''.join(traceback.format_exception(*sys.exc_info()))
        return test_name, filename, [], FAIL, ''.join(traceback.format_exception_only(*sys.exc_info()[:2]))
    else:
        return test_name, filename, [], PASS, None

class Counter:
    def __init__(self):
        self.passed = 0
        self.failed = 0

def get_test_specs(only_spy, only_hdf5, extra_flags):
    base = [
        # FIXME: Move this flag into a per-test parameter so we don't use it everywhere.
        # Don't include backtraces on those expected to fail
        ('compile_fail', (test_compile_fail, (['-fbounds-checks', '1'] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'compile_fail'),
          os.path.join('tests', 'bishop', 'compile_fail'),
         )),
        ('pretty', (test_run_pass, (['-fpretty', '1'] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
         )),
        ('run_pass', (test_run_pass, ([] + extra_flags, {'REALM_BACKTRACE': '1'})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
          os.path.join('tests', 'runtime', 'bugs'),
         )),
    ]
    spy = [
        ('spy', (test_spy, ([] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
         )),
    ]
    hdf5 = [
        ('run_pass', (test_run_pass, ([] + extra_flags, {})),
         (os.path.join('tests', 'hdf5', 'run_pass'),
         )),
    ]

    if only_spy:
        return spy
    elif only_hdf5:
        return hdf5
    else:
        return base

def run_all_tests(thread_count, debug, spy, hdf5, extra_flags, verbose, quiet,
                  only_patterns, skip_patterns):
    thread_pool = multiprocessing.Pool(thread_count)
    results = []

    # Run tests asynchronously.
    tests = get_test_specs(spy, hdf5, extra_flags)
    for test_name, test_fn, test_dirs in tests:
        test_paths = []
        for test_dir in test_dirs:
            if os.path.isfile(test_dir):
                test_paths.append(test_dir)
            else:
                test_paths.extend(
                    path for path in sorted(_glob(test_dir))
                    if os.path.isfile(path) and os.path.splitext(path)[1] in ('.rg', '.md'))

        for test_path in test_paths:
            if only_patterns and not(any(re.search(p,test_path) for p in only_patterns)):
                continue
            if skip_patterns and any(re.search(p,test_path) for p in skip_patterns):
                continue
            results.append((test_name, test_path, thread_pool.apply_async(test_runner, (test_name, test_fn, debug, verbose, test_path))))

    thread_pool.close()

    test_counters = OrderedDict()
    for test_name, test_fn, test_dirs in tests:
        test_counter = Counter()
        test_counters[test_name] = test_counter

    all_saved_temps = []
    try:
        for test_name, filename, result in results:
            while True:
                try:
                    _test_name, _filename, saved_temps, outcome, output = result.get(timeout=60)
                    assert _test_name == test_name and _filename == filename
                except multiprocessing.TimeoutError:
                    print('Potential Hang: (%s) %s' % (test_name, filename))
                    sys.stdout.flush()
                else:
                    break
            if len(saved_temps) > 0:
                all_saved_temps.append((test_name, filename, saved_temps))
            if outcome == PASS:
                if quiet:
                    print('.', end='')
                    sys.stdout.flush()
                else:
                    print('[%sPASS%s] (%s) %s' % (green, clear, test_name, filename))
                if output is not None: print(output)
                test_counters[test_name].passed += 1
            elif outcome == FAIL:
                if quiet: print()
                print('[%sFAIL%s] (%s) %s' % (red, clear, test_name, filename))
                if output is not None: print(output)
                test_counters[test_name].failed += 1
            else:
                raise Exception('Unexpected test outcome %s' % outcome)
    except KeyboardInterrupt:
        raise

    thread_pool.join()

    global_counter = Counter()
    for test_counter in test_counters.values():
        global_counter.passed += test_counter.passed
        global_counter.failed += test_counter.failed
    global_total = global_counter.passed + global_counter.failed

    if len(all_saved_temps) > 0:
        print()
        print('The following temporary files have been saved:')
        print()
        for test_name, filename, saved_temps in all_saved_temps:
            print('[%sFAIL%s] (%s) %s' % (red, clear, test_name, filename))
            for saved_temp in saved_temps:
                print('  %s' % saved_temp)

    if global_total > 0:
        print()
        print('Summary of test results by category:')
        for test_name, test_counter in test_counters.items():
            test_total = test_counter.passed + test_counter.failed
            if test_total > 0:
                print('%24s: Passed %4d of %4d tests (%5.1f%%)' % (
                    '%s' % test_name, test_counter.passed, test_total,
                    float(100*test_counter.passed)/test_total))
        print('    ' + '~'*54)
        print('%24s: Passed %4d of %4d tests (%5.1f%%)' % (
            'total', global_counter.passed, global_total,
            (float(100*global_counter.passed)/global_total)))

    if not verbose and global_counter.failed > 0:
        print()
        print('For detailed information on test failures, run:')
        print('    ./test.py -j1 -v')
        sys.exit(1)

def test_driver(argv):
    parser = argparse.ArgumentParser(description='Regent compiler test suite')
    parser.add_argument('-j',
                        nargs='?',
                        type=int,
                        help='number threads used to compile',
                        dest='thread_count')
    parser.add_argument('--debug', '-g',
                        action='store_true',
                        help='enable debug mode',
                        dest='debug')
    parser.add_argument('--spy', '-s',
                        action='store_true',
                        help='run Legion Spy tests',
                        dest='spy')
    parser.add_argument('--hdf', '--hdf5',
                        action='store_true',
                        help='run HDF5 tests',
                        dest='hdf5')
    parser.add_argument('--extra',
                        action='append',
                        required=False,
                        default=[],
                        help='extra flags to use for each test',
                        dest='extra_flags')
    parser.add_argument('-v',
                        action='store_true',
                        help='display verbose output',
                        dest='verbose')
    parser.add_argument('-q',
                        action='store_true',
                        help='suppress passing test results',
                        dest='quiet')
    parser.add_argument('--only',
                        action='append',
                        default=[],
                        help='only run tests matching pattern',
                        dest='only_patterns')
    parser.add_argument('--skip',
                        action='append',
                        default=[],
                        help='skip tests matching pattern',
                        dest='skip_patterns')
    args = parser.parse_args(argv[1:])

    run_all_tests(
        args.thread_count,
        args.debug,
        args.spy,
        args.hdf5,
        args.extra_flags,
        args.verbose,
        args.quiet,
        args.only_patterns,
        args.skip_patterns)

if __name__ == '__main__':
    test_driver(sys.argv)
<commit_msg>regent: Report both original command and spy command in spy failure.<commit_after>#!/usr/bin/env python

# Copyright 2017 Stanford University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

from __future__ import print_function
import argparse, codecs, glob, itertools, json, multiprocessing, os, optparse, re, shutil, subprocess, sys, tempfile, traceback
from collections import OrderedDict
import regent

_version = sys.version_info.major

if _version == 2: # Python 2.x:
    def _glob(path):
        def visit(result, dirname, filenames):
            for filename in filenames:
                result.append(os.path.join(dirname, filename))
        result = []
        os.path.walk(path, visit, result)
        return result
elif _version == 3: # Python 3.x:
    def _glob(path):
        return [os.path.join(dirname, filename)
                for dirname, _, filenames in os.walk(path)
                for filename in filenames]
else:
    raise Exception('Incompatible Python version')

class TestFailure(Exception):
    def __init__(self, command, output):
        Exception.__init__(self, command, output)
        self.command = command
        self.output = output

def run(filename, debug, verbose, flags, env):
    args = ((['-mg'] if debug else []) +
            [os.path.basename(filename)] + flags +
            ([] if verbose else ['-level', '5']))
    if verbose: print('Running', ' '.join(args))
    proc = regent.regent(
        args,
        stdout=None if verbose else subprocess.PIPE,
        stderr=None if verbose else subprocess.STDOUT,
        env=env,
        cwd=os.path.dirname(os.path.abspath(filename)))
    output, _ = proc.communicate()
    retcode = proc.wait()
    if retcode != 0:
        raise TestFailure(' '.join(args), output.decode('utf-8') if output is not None else None)
    return ' '.join(args)

def run_spy(logfiles, verbose):
    cmd = ['pypy', os.path.join(regent.root_dir(), 'tools', 'legion_spy.py'),
           '--logical',
           '--physical',
           '--cycle',
           # '--sanity', # FIXME: This breaks on several test cases.
           '--leaks',
           # '--geometry', # FIXME: This is *very* slow.
           '--assert-error',
           '--assert-warning'] + logfiles
    if verbose: print('Running', ' '.join(cmd))
    proc = subprocess.Popen(
        cmd,
        stdout=None if verbose else subprocess.PIPE,
        stderr=None if verbose else subprocess.STDOUT)
    output, _ = proc.communicate()
    retcode = proc.wait()
    if retcode != 0:
        raise TestFailure(' '.join(cmd), output.decode('utf-8') if output is not None else None)

_re_label = r'^[ \t\r]*--[ \t]+{label}:[ \t\r]*$\n((^[ \t\r]*--.*$\n)+)'
def find_labeled_text(filename, label):
    re_label = re.compile(_re_label.format(label=label), re.MULTILINE)
    with codecs.open(filename, 'r', encoding='utf-8') as f:
        program_text = f.read()
    match = re.search(re_label, program_text)
    if match is None:
        return None
    match_lines = match.group(1).strip().split('\n')
    match_text = '\n'.join([line.strip()[2:].strip() for line in match_lines])
    return match_text

def find_labeled_flags(filename, prefix):
    flags = [[]]
    flags_text = find_labeled_text(filename, prefix)
    if flags_text is not None:
        flags = json.loads(flags_text)
        assert isinstance(flags, list), "%s declaration must be a json-formatted nested list" % prefix
        for flag in flags:
            assert isinstance(flag, list), "%s declaration must be a json-formatted nested list" % prefix
    return flags

def test_compile_fail(filename, debug, verbose, flags, env):
    expected_failure = find_labeled_text(filename, 'fails-with')
    if expected_failure is None:
        raise Exception('No fails-with declaration in compile_fail test')

    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            run(filename, debug, False, flags + params, env)
    except TestFailure as e:
        failure = e.output
        lines = set(line.strip() for line in failure.strip().split('\n')
                    if len(line.strip()) > 0)
        expected_lines = expected_failure.split('\n')
        for expected_line in expected_lines:
            if expected_line not in lines:
                raise Exception('Command failed:\n%s\n\nExpected failure:\n%s\n\nInstead got:\n%s' % (e.command, expected_failure, failure))
    else:
        raise Exception('Expected failure, but test passed')

def test_run_pass(filename, debug, verbose, flags, env):
    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            run(filename, debug, verbose, flags + params, env)
    except TestFailure as e:
        raise Exception('Command failed:\n%s\n\nOutput:\n%s' % (e.command, e.output))

def test_spy(filename, debug, verbose, flags, env):
    spy_dir = tempfile.mkdtemp(dir=os.path.dirname(os.path.abspath(filename)))
    spy_log = os.path.join(spy_dir, 'spy_%.log')
    spy_flags = ['-level', 'legion_spy=2', '-logfile', spy_log]

    runs_with = find_labeled_flags(filename, 'runs-with')
    try:
        for params in runs_with:
            try:
                cmd = run(filename, debug, verbose, flags + params + spy_flags, env)
            except TestFailure as e:
                raise Exception('Command failed:\n%s\n\nOutput:\n%s' % (e.command, e.output))

            try:
                spy_logs = glob.glob(os.path.join(spy_dir, 'spy_*.log'))
                assert len(spy_logs) > 0
                run_spy(spy_logs, verbose)
            except TestFailure as e:
                raise Exception('Command failed:\n%s\n%s\n\nOutput:\n%s' % (cmd, e.command, e.output))
    finally:
        shutil.rmtree(spy_dir)

red = "\033[1;31m"
green = "\033[1;32m"
clear = "\033[0m"

PASS = 'pass'
FAIL = 'fail'
INTERRUPT = 'interrupt'

def test_runner(test_name, test_closure, debug, verbose, filename):
    test_fn, test_args = test_closure
    saved_temps = []
    try:
        test_fn(filename, debug, verbose, *test_args)
    except KeyboardInterrupt:
        return test_name, filename, [], INTERRUPT, None
    # except driver.CompilerException as e:
    #     if verbose:
    #         return test_name, filename, e.saved_temps, FAIL, ''.join(traceback.format_exception(*sys.exc_info()))
    #     return test_name, filename, e.saved_temps, FAIL, None
    except Exception as e:
        if verbose:
            return test_name, filename, [], FAIL, ''.join(traceback.format_exception(*sys.exc_info()))
        return test_name, filename, [], FAIL, ''.join(traceback.format_exception_only(*sys.exc_info()[:2]))
    else:
        return test_name, filename, [], PASS, None

class Counter:
    def __init__(self):
        self.passed = 0
        self.failed = 0

def get_test_specs(only_spy, only_hdf5, extra_flags):
    base = [
        # FIXME: Move this flag into a per-test parameter so we don't use it everywhere.
        # Don't include backtraces on those expected to fail
        ('compile_fail', (test_compile_fail, (['-fbounds-checks', '1'] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'compile_fail'),
          os.path.join('tests', 'bishop', 'compile_fail'),
         )),
        ('pretty', (test_run_pass, (['-fpretty', '1'] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
         )),
        ('run_pass', (test_run_pass, ([] + extra_flags, {'REALM_BACKTRACE': '1'})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
          os.path.join('tests', 'runtime', 'bugs'),
         )),
    ]
    spy = [
        ('spy', (test_spy, ([] + extra_flags, {})),
         (os.path.join('tests', 'regent', 'run_pass'),
          os.path.join('tests', 'regent', 'perf'),
          os.path.join('tests', 'bishop', 'run_pass'),
          os.path.join('examples'),
          os.path.join('..', 'tutorial'),
         )),
    ]
    hdf5 = [
        ('run_pass', (test_run_pass, ([] + extra_flags, {})),
         (os.path.join('tests', 'hdf5', 'run_pass'),
         )),
    ]

    if only_spy:
        return spy
    elif only_hdf5:
        return hdf5
    else:
        return base

def run_all_tests(thread_count, debug, spy, hdf5, extra_flags, verbose, quiet,
                  only_patterns, skip_patterns):
    thread_pool = multiprocessing.Pool(thread_count)
    results = []

    # Run tests asynchronously.
    tests = get_test_specs(spy, hdf5, extra_flags)
    for test_name, test_fn, test_dirs in tests:
        test_paths = []
        for test_dir in test_dirs:
            if os.path.isfile(test_dir):
                test_paths.append(test_dir)
            else:
                test_paths.extend(
                    path for path in sorted(_glob(test_dir))
                    if os.path.isfile(path) and os.path.splitext(path)[1] in ('.rg', '.md'))

        for test_path in test_paths:
            if only_patterns and not(any(re.search(p,test_path) for p in only_patterns)):
                continue
            if skip_patterns and any(re.search(p,test_path) for p in skip_patterns):
                continue
            results.append((test_name, test_path, thread_pool.apply_async(test_runner, (test_name, test_fn, debug, verbose, test_path))))

    thread_pool.close()

    test_counters = OrderedDict()
    for test_name, test_fn, test_dirs in tests:
        test_counter = Counter()
        test_counters[test_name] = test_counter

    all_saved_temps = []
    try:
        for test_name, filename, result in results:
            while True:
                try:
                    _test_name, _filename, saved_temps, outcome, output = result.get(timeout=60)
                    assert _test_name == test_name and _filename == filename
                except multiprocessing.TimeoutError:
                    print('Potential Hang: (%s) %s' % (test_name, filename))
                    sys.stdout.flush()
                else:
                    break
            if len(saved_temps) > 0:
                all_saved_temps.append((test_name, filename, saved_temps))
            if outcome == PASS:
                if quiet:
                    print('.', end='')
                    sys.stdout.flush()
                else:
                    print('[%sPASS%s] (%s) %s' % (green, clear, test_name, filename))
                if output is not None: print(output)
                test_counters[test_name].passed += 1
            elif outcome == FAIL:
                if quiet: print()
                print('[%sFAIL%s] (%s) %s' % (red, clear, test_name, filename))
                if output is not None: print(output)
                test_counters[test_name].failed += 1
            else:
                raise Exception('Unexpected test outcome %s' % outcome)
    except KeyboardInterrupt:
        raise

    thread_pool.join()

    global_counter = Counter()
    for test_counter in test_counters.values():
        global_counter.passed += test_counter.passed
        global_counter.failed += test_counter.failed
    global_total = global_counter.passed + global_counter.failed

    if len(all_saved_temps) > 0:
        print()
        print('The following temporary files have been saved:')
        print()
        for test_name, filename, saved_temps in all_saved_temps:
            print('[%sFAIL%s] (%s) %s' % (red, clear, test_name, filename))
            for saved_temp in saved_temps:
                print('  %s' % saved_temp)

    if global_total > 0:
        print()
        print('Summary of test results by category:')
        for test_name, test_counter in test_counters.items():
            test_total = test_counter.passed + test_counter.failed
            if test_total > 0:
                print('%24s: Passed %4d of %4d tests (%5.1f%%)' % (
                    '%s' % test_name, test_counter.passed, test_total,
                    float(100*test_counter.passed)/test_total))
        print('    ' + '~'*54)
        print('%24s: Passed %4d of %4d tests (%5.1f%%)' % (
            'total', global_counter.passed, global_total,
            (float(100*global_counter.passed)/global_total)))

    if not verbose and global_counter.failed > 0:
        print()
        print('For detailed information on test failures, run:')
        print('    ./test.py -j1 -v')
        sys.exit(1)

def test_driver(argv):
    parser = argparse.ArgumentParser(description='Regent compiler test suite')
    parser.add_argument('-j',
                        nargs='?',
                        type=int,
                        help='number threads used to compile',
                        dest='thread_count')
    parser.add_argument('--debug', '-g',
                        action='store_true',
                        help='enable debug mode',
                        dest='debug')
    parser.add_argument('--spy', '-s',
                        action='store_true',
                        help='run Legion Spy tests',
                        dest='spy')
    parser.add_argument('--hdf', '--hdf5',
                        action='store_true',
                        help='run HDF5 tests',
                        dest='hdf5')
    parser.add_argument('--extra',
                        action='append',
                        required=False,
                        default=[],
                        help='extra flags to use for each test',
                        dest='extra_flags')
    parser.add_argument('-v',
                        action='store_true',
                        help='display verbose output',
                        dest='verbose')
    parser.add_argument('-q',
                        action='store_true',
                        help='suppress passing test results',
                        dest='quiet')
    parser.add_argument('--only',
                        action='append',
                        default=[],
                        help='only run tests matching pattern',
                        dest='only_patterns')
    parser.add_argument('--skip',
                        action='append',
                        default=[],
                        help='skip tests matching pattern',
                        dest='skip_patterns')
    args = parser.parse_args(argv[1:])

    run_all_tests(
        args.thread_count,
        args.debug,
        args.spy,
        args.hdf5,
        args.extra_flags,
        args.verbose,
        args.quiet,
        args.only_patterns,
        args.skip_patterns)

if __name__ == '__main__':
    test_driver(sys.argv)
<|endoftext|>


<commit_before>from .tree import Tree, Transformer, InlineTransformer
from .common import ParseError, GrammarError
from .lark import Lark
from .utils import inline_args

__version__ = "0.3.1"
<commit_msg>Version bump<commit_after>from .tree import Tree, Transformer, InlineTransformer
from .common import ParseError, GrammarError
from .lark import Lark
from .utils import inline_args

__version__ = "0.3.2"
<|endoftext|>


<commit_before># coding: utf-8

"""
Custom luigi parameters.
"""

__all__ = [
    "NO_STR", "NO_INT", "NO_FLOAT", "is_no_param", "get_param", "TaskInstanceParameter",
    "DurationParameter", "CSVParameter", "NotifyParameter", "NotifyMultiParameter",
    "NotifyMailParameter",
]

import luigi

from law.notification import notify_mail
from law.util import (
    human_duration, parse_duration, time_units, time_unit_aliases, is_lazy_iterable, make_tuple,
)

# make luigi's BoolParameter parsing explicit globally, https://github.com/spotify/luigi/pull/2427
luigi.BoolParameter.parsing = getattr(luigi.BoolParameter, "EXPLICIT_PARSING", "explicit")

# also update existing BoolParameter instances in luigi's config classes to have explicit parsing
for cls in luigi.task.Config.__subclasses__():
    for attr in dir(cls):
        member = getattr(cls, attr)
        if isinstance(member, luigi.BoolParameter):
            member.parsing = luigi.BoolParameter.parsing

#: String value denoting an empty parameter.
NO_STR = "NO_STR"

#: Integer value denoting an empty parameter.
NO_INT = -1

#: Float value denoting an empty parameter.
NO_FLOAT = -1.

def is_no_param(value):
    """
    Checks whether a parameter *value* denotes an empty parameter, i.e., if the value is either
    :py:attr:`NO_STR`, :py:attr:`NO_INT`, or :py:attr:`NO_FLOAT`.
    """
    return value in (NO_STR, NO_INT, NO_FLOAT)

def get_param(value, default=None):
    """
    Returns the passed *value* when it does not refer to an empty parameter value, checked with
    :py:func:`is_no_param`. Otherwise, *default* is returned, which defaults to *None*.
    """
    return default if is_no_param(value) else value

class TaskInstanceParameter(luigi.Parameter):
    """
    Parameter that can be used pass the instance of a task. This class does not implement parameter
    value parsing.
    """

    def serialize(self, x):
        """"""
        return str(x)

class DurationParameter(luigi.Parameter):
    """
    Parameter that interprets a string (or float) value as a duration, represented by a float
    number with a configurable unit. *unit* is forwarded as both the *unit* and *input_unit*
    argument to :py:func:`law.util.parse_duration` which is used for the conversion. For best
    precision, value serialization uses :py:func:`law.util.human_duration` with *colon_format*.
    Example:

    .. code-block:: python

        p = DurationParameter(unit="s")
        p.parse("5")                      # -> 5. (using the unit implicitly)
        p.parse("5s")                     # -> 5.
        p.parse("5m")                     # -> 300.
        p.parse("05:10")                  # -> 310.
        p.parse("5 minutes, 15 seconds")  # -> 310.
        p.serialize(310)                  # -> 05:15

        p = DurationParameter(unit="m")
        p.parse("5")                      # -> 5. (using the unit implicitly)
        p.parse("5s")                     # -> 0.083
        p.parse("5m")                     # -> 5.
        p.parse("05:10")                  # -> 5.167
        p.parse("5 minutes, 15 seconds")  # -> 5.25
        p.serialize(310)                  # -> 05:15

    For more info, see :py:func:`law.util.parse_duration` and :py:func:`law.util.human_duration`.
    """

    def __init__(self, *args, **kwargs):
        """ __init__(unit="s", *args, **kwargs) """
        # validate and set the unit
        self._unit = None
        self.unit = kwargs.pop("unit", "s")

        super(DurationParameter, self).__init__(*args, **kwargs)

    @property
    def unit(self):
        return self._unit

    @unit.setter
    def unit(self, unit):
        unit = time_unit_aliases.get(unit, unit)
        if unit not in time_units:
            raise ValueError("unknown unit '{}', valid values are {}".format(
                unit, time_units.keys()))

        self._unit = unit

    def parse(self, inp):
        """"""
        if not inp:
            return 0.
        else:
            return parse_duration(inp, input_unit=self.unit, unit=self.unit)

    def serialize(self, value):
        """"""
        if not value:
            return "0"
        else:
            value_seconds = parse_duration(value, input_unit=self.unit, unit="s")
            return human_duration(seconds=value_seconds, colon_format=True)

class CSVParameter(luigi.Parameter):
    """
    Parameter that parses a comma-separated value (CSV) and produces a tuple. *cls* can refer to an
    other luigi parameter class that will be used to parse and serialize the particular items.
    Example:

    .. code-block:: python

        p = CSVParameter(cls=luigi.IntParameter, default=(1, 2, 3)]

        p.parse("4,5,6")
        # => (4, 5, 6)

        p.serialize((7, 8, 9))
        # => "7,8,9"

    .. note::

        Due to the way `instance caching
        <https://luigi.readthedocs.io/en/stable/parameters.html#parameter-instance-caching>`__
        is implemented in luigi, parameters should always have hashable values. Therefore, this
        parameter produces a tuple and, in particular, not a list. To avoid undesired side effects,
        the *default* value given to the constructor is also converted to a tuple.

    .. py:attribute:: _inst
       type: cls

        Instance of the luigi parameter class *cls* that is used internally for parameter parsing
        and serialization.
    """

    def __init__(self, *args, **kwargs):
        """ __init__(*args, cls=luigi.Parameter, **kwargs) """
        cls = kwargs.pop("cls", luigi.Parameter)

        # ensure that the default value is a tuple
        if "default" in kwargs:
            kwargs["default"] = make_tuple(kwargs["default"])

        super(CSVParameter, self).__init__(*args, **kwargs)

        self._inst = cls()

    def parse(self, inp):
        """"""
        if not inp:
            return ()
        elif isinstance(inp, (tuple, list)) or is_lazy_iterable(inp):
            return make_tuple(inp)
        else:
            return tuple(self._inst.parse(elem) for elem in inp.split(","))

    def serialize(self, value):
        """"""
        if not value:
            return ""
        else:
            return ",".join(str(self._inst.serialize(elem)) for elem in value)

class NotifyParameter(luigi.BoolParameter):
    """
    Base class for notification parameters. A notification parameter must provide a notification
    transport in :py:meth:`get_transport`, e.g.

    .. code-block:: python

        def get_transport(self):
            return {
                "func": notification_func,
                "raw": True,  # or False
            }

    When a task has a specific notification parameter set to *True* and its run method is decorated
    with the :py:func:`law.notify` function, *notification_func* is called with at least three
    arguments: *success*, *title* and *message*. *success* is a boolean which is *True* when the
    decorated function did not raise an exception. *title* is always a string. When *raw* is *False*
    (the default), *message* is also a string. Otherwise, it is an ordered dictionary containing key
    value pairs describing the message content. All options passed to
    :py:func:`law.decorator.notify` are forwarded to *notification_func* as optional arguments.
    """

    def get_transport(self):
        """
        Method to configure the transport that is toggled by this parameter. Should return a
        dictionary with ``"func"`` and ``"raw"`` (optional) fields.
        """
        return None

class NotifyMultiParameter(NotifyParameter):
    """
    Parameter that takes multiple other :py:class:`NotifyParameter`'s to join their notification
    functionality in a single parameter. Example:

    .. code-block:: python

        class MyTask(law.Task):

            notify = law.NotifyMultiParameter(parameters=[
                law.NotifyMailParameter(significant=False),
                ...  # further NotifyParameters
            ])
    """

    def __init__(self, *args, **kwargs):
        """ __init__(parameters=[], *args, **kwargs) """
        self.parameters = kwargs.pop("parameters", [])

        super(NotifyMultiParameter, self).__init__(*args, **kwargs)

    def get_transport(self):
        """"""
        return [param.get_transport() for param in self.parameters]

class NotifyMailParameter(NotifyParameter):
    """
    Notification parameter defining a basic email transport. Uses
    :py:meth:`law.notification.notify_mail` internally.
    """

    def __init__(self, *args, **kwargs):
        super(NotifyMailParameter, self).__init__(*args, **kwargs)

        if not self.description:
            self.description = "when true, and the task's run method is decorated with " \
                "law.decorator.notify, an email notification is sent once the task finishes"

    @classmethod
    def notify(success, *args, **kwargs):
        """"""
        return notify_mail(*args, **kwargs)

    def get_transport(self):
        """"""
        return {
            "func": self.notify,
            "raw": False,
        }
<commit_msg>Add unique flag to CSVParameter.<commit_after># coding: utf-8

"""
Custom luigi parameters.
"""

__all__ = [
    "NO_STR", "NO_INT", "NO_FLOAT", "is_no_param", "get_param", "TaskInstanceParameter",
    "DurationParameter", "CSVParameter", "NotifyParameter", "NotifyMultiParameter",
    "NotifyMailParameter",
]

import luigi

from law.notification import notify_mail
from law.util import (
    human_duration, parse_duration, time_units, time_unit_aliases, is_lazy_iterable, make_tuple,
    make_unique,
)

# make luigi's BoolParameter parsing explicit globally, https://github.com/spotify/luigi/pull/2427
luigi.BoolParameter.parsing = getattr(luigi.BoolParameter, "EXPLICIT_PARSING", "explicit")

# also update existing BoolParameter instances in luigi's config classes to have explicit parsing
for cls in luigi.task.Config.__subclasses__():
    for attr in dir(cls):
        member = getattr(cls, attr)
        if isinstance(member, luigi.BoolParameter):
            member.parsing = luigi.BoolParameter.parsing

#: String value denoting an empty parameter.
NO_STR = "NO_STR"

#: Integer value denoting an empty parameter.
NO_INT = -1

#: Float value denoting an empty parameter.
NO_FLOAT = -1.

def is_no_param(value):
    """
    Checks whether a parameter *value* denotes an empty parameter, i.e., if the value is either
    :py:attr:`NO_STR`, :py:attr:`NO_INT`, or :py:attr:`NO_FLOAT`.
    """
    return value in (NO_STR, NO_INT, NO_FLOAT)

def get_param(value, default=None):
    """
    Returns the passed *value* when it does not refer to an empty parameter value, checked with
    :py:func:`is_no_param`. Otherwise, *default* is returned, which defaults to *None*.
    """
    return default if is_no_param(value) else value

class TaskInstanceParameter(luigi.Parameter):
    """
    Parameter that can be used pass the instance of a task. This class does not implement parameter
    value parsing.
    """

    def serialize(self, x):
        """"""
        return str(x)

class DurationParameter(luigi.Parameter):
    """
    Parameter that interprets a string (or float) value as a duration, represented by a float
    number with a configurable unit. *unit* is forwarded as both the *unit* and *input_unit*
    argument to :py:func:`law.util.parse_duration` which is used for the conversion. For best
    precision, value serialization uses :py:func:`law.util.human_duration` with *colon_format*.
    Example:

    .. code-block:: python

        p = DurationParameter(unit="s")
        p.parse("5")                      # -> 5. (using the unit implicitly)
        p.parse("5s")                     # -> 5.
        p.parse("5m")                     # -> 300.
        p.parse("05:10")                  # -> 310.
        p.parse("5 minutes, 15 seconds")  # -> 310.
        p.serialize(310)                  # -> 05:15

        p = DurationParameter(unit="m")
        p.parse("5")                      # -> 5. (using the unit implicitly)
        p.parse("5s")                     # -> 0.083
        p.parse("5m")                     # -> 5.
        p.parse("05:10")                  # -> 5.167
        p.parse("5 minutes, 15 seconds")  # -> 5.25
        p.serialize(310)                  # -> 05:15

    For more info, see :py:func:`law.util.parse_duration` and :py:func:`law.util.human_duration`.
    """

    def __init__(self, *args, **kwargs):
        """ __init__(unit="s", *args, **kwargs) """
        # validate and set the unit
        self._unit = None
        self.unit = kwargs.pop("unit", "s")

        super(DurationParameter, self).__init__(*args, **kwargs)

    @property
    def unit(self):
        return self._unit

    @unit.setter
    def unit(self, unit):
        unit = time_unit_aliases.get(unit, unit)
        if unit not in time_units:
            raise ValueError("unknown unit '{}', valid values are {}".format(
                unit, time_units.keys()))

        self._unit = unit

    def parse(self, inp):
        """"""
        if not inp:
            return 0.
        else:
            return parse_duration(inp, input_unit=self.unit, unit=self.unit)

    def serialize(self, value):
        """"""
        if not value:
            return "0"
        else:
            value_seconds = parse_duration(value, input_unit=self.unit, unit="s")
            return human_duration(seconds=value_seconds, colon_format=True)

class CSVParameter(luigi.Parameter):
    """
    Parameter that parses a comma-separated value (CSV) and produces a tuple. *cls* can refer to an
    other parameter class that will be used to parse and serialize the particular items.

    When *unique* is *True*, both parsing and serialization methods make sure that values are
    unique.

    Example:

    .. code-block:: python

        p = CSVParameter(cls=luigi.IntParameter)

        p.parse("4,5,6,6")
        # => (4, 5, 6, 6)

        p.serialize((7, 8, 9))
        # => "7,8,9"

        p = CSVParameter(cls=luigi.IntParameter, unique=True)

        p.parse("4,5,6,6")
        # => (4, 5, 6)

    .. note::

        Due to the way `instance caching
        <https://luigi.readthedocs.io/en/stable/parameters.html#parameter-instance-caching>`__
        is implemented in luigi, parameters should always have hashable values. Therefore, this
        parameter produces a tuple and, in particular, not a list. To avoid undesired side effects,
        the *default* value given to the constructor is also converted to a tuple.

    .. py:attribute:: _inst
       type: cls

        Instance of the luigi parameter class *cls* that is used internally for parameter parsing
        and serialization.
    """

    def __init__(self, *args, **kwargs):
        """ __init__(*args, cls=luigi.Parameter, unique=False, **kwargs) """
        self._cls = kwargs.pop("cls", luigi.Parameter)
        self._unique = kwargs.pop("unique", False)

        # ensure that the default value is a tuple
        if "default" in kwargs:
            kwargs["default"] = make_tuple(kwargs["default"])

        super(CSVParameter, self).__init__(*args, **kwargs)

        self._inst = self._cls()

    def parse(self, inp):
        """"""
        if not inp:
            ret = tuple()
        elif isinstance(inp, (tuple, list)) or is_lazy_iterable(inp):
            ret = make_tuple(inp)
        else:
            ret = tuple(self._inst.parse(elem) for elem in inp.split(","))

        if self._unique:
            ret = make_unique(ret)

        return ret

    def serialize(self, value):
        """"""
        if not value:
            return ""
        else:
            if self._unique:
                value = make_unique(value)
            return ",".join(str(self._inst.serialize(elem)) for elem in value)

class NotifyParameter(luigi.BoolParameter):
    """
    Base class for notification parameters. A notification parameter must provide a notification
    transport in :py:meth:`get_transport`, e.g.

    .. code-block:: python

        def get_transport(self):
            return {
                "func": notification_func,
                "raw": True,  # or False
            }

    When a task has a specific notification parameter set to *True* and its run method is decorated
    with the :py:func:`law.notify` function, *notification_func* is called with at least three
    arguments: *success*, *title* and *message*. *success* is a boolean which is *True* when the
    decorated function did not raise an exception. *title* is always a string. When *raw* is *False*
    (the default), *message* is also a string. Otherwise, it is an ordered dictionary containing key
    value pairs describing the message content. All options passed to
    :py:func:`law.decorator.notify` are forwarded to *notification_func* as optional arguments.
    """

    def get_transport(self):
        """
        Method to configure the transport that is toggled by this parameter. Should return a
        dictionary with ``"func"`` and ``"raw"`` (optional) fields.
        """
        return None

class NotifyMultiParameter(NotifyParameter):
    """
    Parameter that takes multiple other :py:class:`NotifyParameter`'s to join their notification
    functionality in a single parameter. Example:

    .. code-block:: python

        class MyTask(law.Task):

            notify = law.NotifyMultiParameter(parameters=[
                law.NotifyMailParameter(significant=False),
                ...  # further NotifyParameters
            ])
    """

    def __init__(self, *args, **kwargs):
        """ __init__(parameters=[], *args, **kwargs) """
        self.parameters = kwargs.pop("parameters", [])

        super(NotifyMultiParameter, self).__init__(*args, **kwargs)

    def get_transport(self):
        """"""
        return [param.get_transport() for param in self.parameters]

class NotifyMailParameter(NotifyParameter):
    """
    Notification parameter defining a basic email transport. Uses
    :py:meth:`law.notification.notify_mail` internally.
    """

    def __init__(self, *args, **kwargs):
        super(NotifyMailParameter, self).__init__(*args, **kwargs)

        if not self.description:
            self.description = "when true, and the task's run method is decorated with " \
                "law.decorator.notify, an email notification is sent once the task finishes"

    @classmethod
    def notify(success, *args, **kwargs):
        """"""
        return notify_mail(*args, **kwargs)

    def get_transport(self):
        """"""
        return {
            "func": self.notify,
            "raw": False,
        }
<|endoftext|>


<commit_before>import discord

from __main__ import send_cmd_help
from discord.ext import commands
from bs4 import BeautifulSoup

class League:
    def __init__(self, bot):
        self.bot = bot

    @commands.group(pass_context = True)
    async def opgg(self, ctx):
        """Shows a summoners account on OPGG"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            return

    @commands.group(pass_context = True)
    async def league(self, ctx):
        """Shows a page on http://leagueoflegends.wikia.com/"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            await self.bot.say("```\nYou have to put the ' in a if it is in a champion name.\nYou also have to capitalize champion names\n```")

    @league.command()
    async def champion(self, *, champion):
        """Finds a champion on http://leagueoflegends.wikia.com/."""
        champion1 = "<http://leagueoflegends.wikia.com/wiki/" + champion + ">"
        champion1 = champion1.replace("'", "%27")
        await self.bot.say(champion1.replace(" ", "_"))
        champion2 = champion.replace(" ", "")
        champion2 = champion2.replace("'", "")
        await self.bot.say("<http://champion.gg/champion/" + champion2 + ">")

    @opgg.command()
    async def na(self, *, summoner):
        await self.bot.say("http://na.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def eune(self, *, summoner):
        await self.bot.say("http://eune.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def euw(self, *, summoner):
        await self.bot.say("http://euw.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["kr"])
    async def korea(self, *, summoner):
        await self.bot.say("http://www.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["jp"])
    async def japan(self, *, summoner):
        await self.bot.say("http://jp.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["br"])
    async def brazil(self, *, summoner):
        await self.bot.say("http://br.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["tr"])
    async def turkey(self, *, summoner):
        await self.bot.say("http://tr.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["oce"])
    async def oceania(self, *, summoner):
        await self.bot.say("http://oce.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def las(self, *, summoner):
        await self.bot.say("http://las.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def lan(self, *, summoner):
        await self.bot.say("http://lan.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["ru"])
    async def russia(self, *, summoner):
        await self.bot.say("http://ru.op.gg/summoner/userName=" + summoner)

def setup(bot):
    bot.add_cog(League(bot))
<commit_msg>attempted using BS4<commit_after>import discord
import aiohttp

from __main__ import send_cmd_help
from discord.ext import commands

try: # check if BeautifulSoup4 is installed
	from bs4 import BeautifulSoup
	soupAvailable = True
except:
	soupAvailable = False

class League:
    def __init__(self, bot):
        self.bot = bot

    @commands.group(pass_context = True)
    async def opgg(self, ctx):
        """Shows a summoners account on OPGG"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            return

    @commands.group(pass_context = True)
    async def league(self, ctx):
        """Shows a page on http://leagueoflegends.wikia.com/"""
        if ctx.invoked_subcommand is None:
            await send_cmd_help(ctx)
            await self.bot.say("```\nYou have to put the ' in a if it is in a champion name.\nYou also have to capitalize champion names\n```")

    @league.command()
    async def champion(self, *, champion):
        """Finds a champion on http://leagueoflegends.wikia.com/."""
        champion = champion.title()
        champion1 = "<http://leagueoflegends.wikia.com/wiki/" + champion + ">"
        champion1 = champion1.replace("'", "%27")
        await self.bot.say(champion1.replace(" ", "_"))
        champion2 = champion.replace(" ", "")
        champion2 = champion2.replace("'", "")
        await self.bot.say("<http://champion.gg/champion/" + champion2 + ">")

    #@league.command(pass_context=True)
    #async def ability(self, ctx, *, champion):
    #    champion1 = "<http://leagueoflegends.wikia.com/wiki/" + champion + ">"
    #    champion1 = champion1.replace("'", "%27")
    #    champion1 = champion1.title() + "/Abilities"
    #    url = champion1.replace(" ", "_") #build the web adress
    #    async with aiohttp.get(url) as response:
    #        soupObject = BeautifulSoup(await response.text(), "html.parser")
    #    try:
    #        online = soupObject.find(class_='champion-icon').find('data-champion=\"{}\"').find('strong').get_text()
    #        await self.bot.say(online + ' players are playing this game at the moment')
    #    except:
    #        await self.bot.say("Couldn't load amount of players. No one is playing this game anymore or there's an error.")

    @opgg.command()
    async def na(self, *, summoner):
        await self.bot.say("http://na.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def eune(self, *, summoner):
        await self.bot.say("http://eune.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def euw(self, *, summoner):
        await self.bot.say("http://euw.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["kr"])
    async def korea(self, *, summoner):
        await self.bot.say("http://www.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["jp"])
    async def japan(self, *, summoner):
        await self.bot.say("http://jp.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["br"])
    async def brazil(self, *, summoner):
        await self.bot.say("http://br.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["tr"])
    async def turkey(self, *, summoner):
        await self.bot.say("http://tr.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["oce"])
    async def oceania(self, *, summoner):
        await self.bot.say("http://oce.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def las(self, *, summoner):
        await self.bot.say("http://las.op.gg/summoner/userName=" + summoner)

    @opgg.command()
    async def lan(self, *, summoner):
        await self.bot.say("http://lan.op.gg/summoner/userName=" + summoner)

    @opgg.command(aliases = ["ru"])
    async def russia(self, *, summoner):
        await self.bot.say("http://ru.op.gg/summoner/userName=" + summoner)

def setup(bot):
    if soupAvailable:
        bot.add_cog(League(bot))
    else:
        raise RuntimeError("You need to run `pip3 install beautifulsoup4`")
<|endoftext|>


<commit_before>import random
import copy
import timeit

class Solution:
    def sort(self,nums):
        vs = copy.deepcopy(nums)
        num = []
        for i in xrange(len(vs)):
            minf = min(vs)
            num.append(minf)
            vs.remove(minf)
        return num

    def bubbleSort(self, nums):
        vs = copy.deepcopy(nums)
        for i in xrange(len(vs)):
            hasBubble = False
            for j in xrange(len(vs)-1-i):
                if vs[j] > vs[j+1]:
                    v = vs[j+1]
                    vs[j+1] = vs[j]
                    vs[j] = v
                    hasBubble = True
            if not hasBubble:
                break
        return vs

def test_1(v, refv):
    assert (Solution().sort(v) == refv)

def test_2(v, refv):
    assert (Solution().bubbleSort(v) == refv)

if __name__ == "__main__":
    random.seed(0)
    refm = range(10000)
    #refm = range(10)
    m = copy.deepcopy(refm)
    random.shuffle(m)

    print timeit.timeit(stmt='assert sorted(m) == refm', setup="from __main__ import test_1, m, refm", number=1)
    print timeit.timeit(stmt='test_1(m, refm)', setup="from __main__ import test_1, m, refm", number=1)
    print timeit.timeit(stmt='test_2(m, refm)', setup="from __main__ import test_2, m, refm", number=1)
<commit_msg>add quickSort<commit_after>import random
import copy
import timeit

class Solution:
    def sort(self,nums):
        vs = copy.deepcopy(nums)
        num = []
        for i in xrange(len(vs)):
            minf = min(vs)
            num.append(minf)
            vs.remove(minf)
        return num

    def bubbleSort(self, nums):
        vs = copy.deepcopy(nums)
        for i in xrange(len(vs)):
            hasBubble = False
            for j in xrange(len(vs)-1-i):
                if vs[j] > vs[j+1]:
                    v = vs[j+1]
                    vs[j+1] = vs[j]
                    vs[j] = v
                    hasBubble = True
            if not hasBubble:
                break
        return vs

    def quickSort(self, nums):
        less = []
        equal = []
        bigger = []
        if not nums:
            return []
        pivot = nums[0]
        for x in nums:
            if x < pivot:
                less.append(x)
            elif x == pivot:
                equal.append(x)
            else:
                assert (x > pivot)
                bigger.append(x)
        return self.quickSort(less) + equal + self.quickSort(bigger)

def test_1(v, refv):
    assert (Solution().sort(v) == refv)

def test_2(v, refv):
    assert (Solution().bubbleSort(v) == refv)

def test_quicksort(v, refv):
    assert (Solution().quickSort(v) == refv)

if __name__ == "__main__":
    random.seed(0)
    refm = range(10000)
    #refm = range(10)
    m = copy.deepcopy(refm)
    random.shuffle(m)

    print timeit.timeit(stmt='assert sorted(m) == refm', setup="from __main__ import test_1, m, refm", number=1)
    print timeit.timeit(stmt='test_1(m, refm)', setup="from __main__ import test_1, m, refm", number=1)
    print timeit.timeit(stmt='test_2(m, refm)', setup="from __main__ import test_2, m, refm", number=1)
    print timeit.timeit(stmt='test_quicksort(m, refm)', setup="from __main__ import test_quicksort, m, refm", number=1)
<|endoftext|>


<commit_before># coding: utf-8

class Object(object):
    def __init__(self, data=None, **kwargs):
        self._data = []
        if data is not None:
            self.extend(data)
        if kwargs != {}:
            self.extend(kwargs)

    @property
    def data(self):
        return self._data

    @property
    def object_class(self):
        return self.data[0][0]

    @object_class.setter
    def object_class(self, new_class):
        self.data[0] = (new_class, self.object_key)

    @property
    def object_key(self):
        return self.data[0][1]

    @object_key.setter
    def object_key(self, new_key):
        self.data[0] = (self.object_class, new_key)

    @property
    def type(self):
        return self.object_class

    @property
    def key(self):
        return self.object_key

    @property
    def primary_key(self):
        return self.object_key

    def extend(self, ex):
        if isinstance(ex, list):
            for offset, item in enumerate(ex):
                if isinstance(item, (tuple, list)):
                    if len(item) != 2:
                        raise ValueError("offset {}: expected tuple of length 2, got {}".format(offset))
                    elif not isinstance(item[0], str):
                        raise ValueError("offset {}: expected key to be of type str, got {}".format(offset, type(item[0])))
                    elif not isinstance(item[1], str):
                        raise ValueError("offset {}: expected value to be of type str, got {}".format(offset, type(item[1])))
                else:
                    raise TypeError("offset {}: expected entry to be of type tuple, got {}".format(offset, item))
            for key, value in ex:
                self.add(key, value)
        elif isinstance(ex, dict):
            for key, value in ex:
                if not isinstance(key, str):
                    raise ValueError("expected key to be of type str, got {}".format(type(key)))
                elif not isinstance(value, (str, list)):
                    raise ValueError("expected value to be of type str or list, got {}".format(type(value)))
                if isinstance(value, list):
                    for off, val in enumerate(value):
                        if not isinstance(val, str):
                            raise ValueError("key {} offset {}: expected value to be of type str, got {}".format(key, off, type(val)))
            for key, value in ex:
                if isinstance(value, list):
                    for val in value:
                        self.add(key, val)
                else:
                    self.add(key, value)
            pass
        elif isinstance(ex, str):
            self.extend(parse_object(ex.splitlines()))
        elif isinstance(ex, Object):
            self.extend(ex.data)
        elif hasattr(ex, "__iter__"):
            self.extend(list(ex))
        else:
            raise TypeError("Expected ex to be dict, list, str, or lglass.object.Object, got {}".format(type(ex)))

    def __getitem__(self, key):
        if isinstance(key, str):
            try:
                return list(self.get(key))[0]
            except IndexError:
                raise KeyError(repr(key))
        elif isinstance(key, (int, slice)):
            return self.data[key]
        raise TypeError("Expected key to be str or int, got {}".format(type(key)))

    def __setitem__(self, key, value):
        if isinstance(key, int):
            pass
        elif isinstance(key, str):
            if key not in self:
                self.append(key, value)

    def __delitem__(self, key):
        return self.remove(key)

    def __contains__(self, key):
        for key1 in self.keys():
            if key1 == key:
                return True
        return False

    def __len__(self):
        return len(self.data)

    def get(self, key):
        return (v for k, v in self._data if k == key)

    def getfirst(self, key, default=None):
        return next(self.get(key), default)

    def add(self, key, value, index=None):
        if index is not None:
            return self.insert(index, key, value)
        return self.append(key, value)

    def append(self, key, value):
        return self._data.append((key, value))

    def insert(self, index, key, value):
        return self._data.insert(index, (key, value))

    def indices(self, key):
        return [i for i, (k, v) in enumerate(self.data) if k == key]

    def remove(self, key, nth=None):
        if isinstance(key, int):
            del self._data[key]
            return
        self._data = [kvpair for kvpair in self._data if kvpair[0] != key]

    def items(self):
        return iter(self.data)

    def keys(self):
        return (key for key, _ in self.items())

    def values(self):
        return (value for _, value in self.items())

    def pretty_print(self, min_padding=0, add_padding=8):
        padding = max(max((len(k) for k in self.keys()), default=0), min_padding) + add_padding
        for key, value in self:
            value_lines = value.splitlines() or [""]
            record = "{key}:{pad}{value}\n".format(
                    key=key,
                    pad=" " * (padding - len(key)),
                    value=value_lines[0])
            for line in value_lines[1:]:
                record += "{pad}{value}\n".format(
                        pad=" " * (padding + 1),
                        value=line)
            yield record

    def __str__(self):
        return "".join(self.pretty_print())

    def __hash__(self):
        return hash((self.type, self.key))

    def __eq__(self, other):
        if hash(self) != hash(other):
            return false
        try:
            return self.data == other.data
        except AttributeError:
            return False

    def __ne__(self, other):
        return not self == other

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

    @classmethod
    def from_file(cls, fh):
        return cls(fh.read())

# TODO rewrite object parser
def parse_object(lines, pragmas={}):
	r'''This is a simple RPSL parser which expects an iterable which yields lines.
	This parser processes the object format, not the policy format. The object
	format used by this parser is similar to the format described by the RFC:
	Each line consists of key and value, which are separated by a colon ':'.
	The ':' can be surrounded by whitespace characters including line breaks,
	because this parser doesn't split the input into lines; it's newline unaware.
	The format also supports line continuations by beginning a new line of input
	with a whitespace character. This whitespace character is stripped, but the
	parser will produce a '\n' in the resulting value. Line continuations are
	only possible for the value part, which means, that the key and ':' must be
	on the same line of input.

	We also support an extended format using pragmas, which can define the
	processing rules like line-break type, and whitespace preservation. Pragmas
	are on their own line, which must begin with "%!", followed by any
	amount of whitespace, "pragma", at least one whitespace, followed by the
	pragma-specific part.

	The following pragmas are supported:

		``%! pragma whitespace-preserve [on|off]``
				Preserve any whitespace of input in keys and values and don't strip
				whitespace.

		``%! pragma newline-type [cr|lf|crlf|none]``
				Define type of newline by choosing between cr "Mac OS 9", lf "Unix",
				crlf "Windows" and none.

		``%! pragma rfc``
				Reset all pragmas to the RFC-conform values.

		``%! pragma stop-at-empty-line [on|off]``
				Enforces the parser to stop at an empty line

		``%! pragma condense-whitespace [on|off]``
				Replace any sequence of whitespace characters with simple space (' ')

		``%! pragma strict-ripe [on|off]``
				Do completely RIPE database compilant parsing, e.g. don't allow any
				space between key and the colon.

		``%! pragma hash-comment [on|off]``
				Recognize hash '#' as beginning of comment
	'''
	result = []
	default_pragmas = {
		"whitespace-preserve": False,
		"newline-type": "lf",
		"stop-at-empty-line": False,
		"condense-whitespace": False,
		"strict-ripe": False,
		"hash-comment": False
	}
	_pragmas = dict(default_pragmas)
	_pragmas.update(pragmas)
	pragmas = _pragmas

	for line in lines:
		if line.startswith("%!"):
			# this line defines a parser instruction, which should be a pragma
			values = line[2:].strip().split()
			if len(values) <= 1:
				raise ValueError("Syntax error: Expected pragma type after 'pragma'")
			if values[0] != "pragma":
				raise ValueError("Syntax error: Only pragmas are allowed as parser instructions")
			if values[1] == "rfc":
				pragmas.update(default_pragmas)
			elif values[1] in {"whitespace-preserve", "stop-at-empty-line",
				"condense-whitespace", "strict-ripe", "hash-comment"}:
				try:
					if values[2] not in {"on", "off"}:
						raise ValueError("Syntax error: Expected 'on' or 'off' as value for '{}' pragma".format(values[1]))
					pragmas[values[1]] = True if values[2] == "on" else False
				except IndexError:
					raise ValueError("Syntax error: Expected value after '{}'".format(values[1]))
			elif values[1] == "newline-type":
				try:
					if values[2] not in ["cr", "lf", "crlf", "none"]:
						raise ValueError("Syntax error: Expected 'cr', 'lf', 'crlf' or 'none' as value for 'newline-type' pragma")
					pragmas["newline-type"] = values[2]
				except IndexError:
					raise ValueError("Syntax error: Expected value after 'newline-type'")
			else:
				raise ValueError("Syntax error: Unknown pragma: {}".format(values))
			continue

		# remove any comments (text after % and #)
		line = line.split("%")[0]
		if pragmas["hash-comment"]:
			line = line.split("#")[0]

		# continue if line is empty
		if not line.strip():
			if pragmas["stop-at-empty-line"] and len(result) != 0:
				break
			continue

		# check for line continuations
		if line[0] in [' ', '\t', "+"]:
			line = line[1:]
			if not pragmas["whitespace-preserve"]:
				line = line.strip()
			entry = result.pop()
			value = ({
				"cr": "\r",
				"lf": "\n",
				"crlf": "\r\n",
				"none": ""
			}[pragmas["newline-type"]]).join([entry[1], line])
			result.append((entry[0], value))
			continue

		try:
			key, value = line.split(":", 1)
		except ValueError:
			raise ValueError("Syntax error: Missing value")

		if pragmas["strict-ripe"]:
			if not re.match("^[a-zA-Z0-9-]+$", key):
				raise ValueError("Syntax error: Key doesn't match RIPE database requirements")

		if not pragmas["whitespace-preserve"]:
			key = key.strip()
			value = value.strip()

		if pragmas["condense-whitespace"]:
			import re
			value = re.sub(r"[\s]+", " ", value, flags=re.M|re.S)

		result.append((key, value))

	return result

if __name__ == "__main__":
    import argparse
    import sys

    argparser = argparse.ArgumentParser(description="Pretty-print objects")
    argparser.add_argument("--min-padding", help="Minimal padding between key and value", type=int, default=0)
    argparser.add_argument("--add-padding", help="Additional padding between key and value", type=int, default=8)
    argparser.add_argument("files", nargs='*', help="Input files")

    args = argparser.parse_args()

    options = dict(
            min_padding=args.min_padding,
            add_padding=args.add_padding)

    if not args.files:
        obj = Object.from_file(sys.stdin)
        print("".join(obj.pretty_print(**options)))
    else:
        for f in args.files:
            with open(f) as fh:
                obj = Object.from_file(fh)
                print("".join(obj.pretty_print(**options)))

<commit_msg>Reformat parse_object code<commit_after># coding: utf-8

class Object(object):
    def __init__(self, data=None, **kwargs):
        self._data = []
        if data is not None:
            self.extend(data)
        if kwargs != {}:
            self.extend(kwargs)

    @property
    def data(self):
        return self._data

    @property
    def object_class(self):
        return self.data[0][0]

    @object_class.setter
    def object_class(self, new_class):
        self.data[0] = (new_class, self.object_key)

    @property
    def object_key(self):
        return self.data[0][1]

    @object_key.setter
    def object_key(self, new_key):
        self.data[0] = (self.object_class, new_key)

    @property
    def type(self):
        return self.object_class

    @property
    def key(self):
        return self.object_key

    @property
    def primary_key(self):
        return self.object_key

    def extend(self, ex):
        if isinstance(ex, list):
            for offset, item in enumerate(ex):
                if isinstance(item, (tuple, list)):
                    if len(item) != 2:
                        raise ValueError("offset {}: expected tuple of length 2, got {}".format(offset))
                    elif not isinstance(item[0], str):
                        raise ValueError("offset {}: expected key to be of type str, got {}".format(offset, type(item[0])))
                    elif not isinstance(item[1], str):
                        raise ValueError("offset {}: expected value to be of type str, got {}".format(offset, type(item[1])))
                else:
                    raise TypeError("offset {}: expected entry to be of type tuple, got {}".format(offset, item))
            for key, value in ex:
                self.add(key, value)
        elif isinstance(ex, dict):
            for key, value in ex:
                if not isinstance(key, str):
                    raise ValueError("expected key to be of type str, got {}".format(type(key)))
                elif not isinstance(value, (str, list)):
                    raise ValueError("expected value to be of type str or list, got {}".format(type(value)))
                if isinstance(value, list):
                    for off, val in enumerate(value):
                        if not isinstance(val, str):
                            raise ValueError("key {} offset {}: expected value to be of type str, got {}".format(key, off, type(val)))
            for key, value in ex:
                if isinstance(value, list):
                    for val in value:
                        self.add(key, val)
                else:
                    self.add(key, value)
            pass
        elif isinstance(ex, str):
            self.extend(parse_object(ex.splitlines()))
        elif isinstance(ex, Object):
            self.extend(ex.data)
        elif hasattr(ex, "__iter__"):
            self.extend(list(ex))
        else:
            raise TypeError("Expected ex to be dict, list, str, or lglass.object.Object, got {}".format(type(ex)))

    def __getitem__(self, key):
        if isinstance(key, str):
            try:
                return list(self.get(key))[0]
            except IndexError:
                raise KeyError(repr(key))
        elif isinstance(key, (int, slice)):
            return self.data[key]
        raise TypeError("Expected key to be str or int, got {}".format(type(key)))

    def __setitem__(self, key, value):
        if isinstance(key, (int, slice)):
            self.data[key] = value
        elif isinstance(key, str):
            if key not in self:
                self.append(key, value)
            else:
                index = self.indices(key)[0]
                self.remove(key)
                self.insert(index, key, value)

    def __delitem__(self, key):
        if isinstance(key, (int, slice)):
            del self.data[key]
        else:
            self.remove(key)

    def __contains__(self, key):
        for key1 in self.keys():
            if key1 == key:
                return True
        return False

    def __len__(self):
        return len(self.data)

    def get(self, key):
        return (v for k, v in self._data if k == key)

    def getfirst(self, key, default=None):
        return next(self.get(key), default)

    def add(self, key, value, index=None):
        if index is not None:
            return self.insert(index, key, value)
        return self.append(key, value)

    def append(self, key, value):
        return self._data.append((key, value))

    def insert(self, index, key, value):
        return self._data.insert(index, (key, value))

    def indices(self, key):
        return [i for i, (k, v) in enumerate(self.data) if k == key]

    def remove(self, key):
        if isinstance(key, int):
            del self._data[key]
            return
        self._data = [kvpair for kvpair in self._data if kvpair[0] != key]

    def items(self):
        return iter(self.data)

    def keys(self):
        return (key for key, _ in self.items())

    def values(self):
        return (value for _, value in self.items())

    def pretty_print(self, min_padding=0, add_padding=8):
        padding = max(max((len(k) for k in self.keys()), default=0), min_padding) + add_padding
        for key, value in self:
            value_lines = value.splitlines() or [""]
            record = "{key}:{pad}{value}\n".format(
                    key=key,
                    pad=" " * (padding - len(key)),
                    value=value_lines[0])
            for line in value_lines[1:]:
                record += "{pad}{value}\n".format(
                        pad=" " * (padding + 1),
                        value=line)
            yield record

    def __str__(self):
        return "".join(self.pretty_print())

    def __hash__(self):
        return hash((self.type, self.key))

    def __eq__(self, other):
        if hash(self) != hash(other):
            return false
        try:
            return self.data == other.data
        except AttributeError:
            return False

    def __ne__(self, other):
        return not self == other

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

    def copy(self):
        return self.__class__(self.data)

    @classmethod
    def from_file(cls, fh):
        return cls(fh.read())

def parse_objects(lines, pragmas=None):
    if pragmas is None:
        pragmas = {}
    else:
        pragmas = dict(pragmas)
    pragmas["stop-at-empty-line"] = True
    lines_iter = iter(lines)
    try:
        while True:
            obj = parse_object(lines_iter, pragmas=pragmas)
            if obj:
                yield obj
            else:
                next(lines_iter)
    except StopIteration:
        pass

# TODO rewrite object parser
def parse_object(lines, pragmas={}):
    r'''This is a simple RPSL parser which expects an iterable which yields lines.
    This parser processes the object format, not the policy format. The object
    format used by this parser is similar to the format described by the RFC:
    Each line consists of key and value, which are separated by a colon ':'.
    The ':' can be surrounded by whitespace characters including line breaks,
    because this parser doesn't split the input into lines; it's newline unaware.
    The format also supports line continuations by beginning a new line of input
    with a whitespace character. This whitespace character is stripped, but the
    parser will produce a '\n' in the resulting value. Line continuations are
    only possible for the value part, which means, that the key and ':' must be
    on the same line of input.

    We also support an extended format using pragmas, which can define the
    processing rules like line-break type, and whitespace preservation. Pragmas
    are on their own line, which must begin with "%!", followed by any
    amount of whitespace, "pragma", at least one whitespace, followed by the
    pragma-specific part.

    The following pragmas are supported:

        ``%! pragma whitespace-preserve [on|off]``
                Preserve any whitespace of input in keys and values and don't strip
                whitespace.

        ``%! pragma newline-type [cr|lf|crlf|none]``
                Define type of newline by choosing between cr "Mac OS 9", lf "Unix",
                crlf "Windows" and none.

        ``%! pragma rfc``
                Reset all pragmas to the RFC-conform values.

        ``%! pragma stop-at-empty-line [on|off]``
                Enforces the parser to stop at an empty line

        ``%! pragma condense-whitespace [on|off]``
                Replace any sequence of whitespace characters with simple space (' ')

        ``%! pragma strict-ripe [on|off]``
                Do completely RIPE database compilant parsing, e.g. don't allow any
                space between key and the colon.

        ``%! pragma hash-comment [on|off]``
                Recognize hash '#' as beginning of comment
    '''
    result = []
    default_pragmas = {
        "whitespace-preserve": False,
        "newline-type": "lf",
        "stop-at-empty-line": False,
        "condense-whitespace": False,
        "strict-ripe": False,
        "hash-comment": False
    }
    _pragmas = dict(default_pragmas)
    _pragmas.update(pragmas)
    pragmas = _pragmas

    for line in lines:
        if line.startswith("%!"):
            # this line defines a parser instruction, which should be a pragma
            values = line[2:].strip().split()
            if len(values) <= 1:
                raise ValueError("Syntax error: Expected pragma type after 'pragma'")
            if values[0] != "pragma":
                raise ValueError("Syntax error: Only pragmas are allowed as parser instructions")
            if values[1] == "rfc":
                pragmas.update(default_pragmas)
            elif values[1] in {"whitespace-preserve", "stop-at-empty-line",
                "condense-whitespace", "strict-ripe", "hash-comment"}:
                try:
                    if values[2] not in {"on", "off"}:
                        raise ValueError("Syntax error: Expected 'on' or 'off' as value for '{}' pragma".format(values[1]))
                    pragmas[values[1]] = True if values[2] == "on" else False
                except IndexError:
                    raise ValueError("Syntax error: Expected value after '{}'".format(values[1]))
            elif values[1] == "newline-type":
                try:
                    if values[2] not in ["cr", "lf", "crlf", "none"]:
                        raise ValueError("Syntax error: Expected 'cr', 'lf', 'crlf' or 'none' as value for 'newline-type' pragma")
                    pragmas["newline-type"] = values[2]
                except IndexError:
                    raise ValueError("Syntax error: Expected value after 'newline-type'")
            else:
                raise ValueError("Syntax error: Unknown pragma: {}".format(values))
            continue

        # remove any comments (text after % and #)
        line = line.split("%")[0]
        if pragmas["hash-comment"]:
            line = line.split("#")[0]

        # continue if line is empty
        if not line.strip():
            if pragmas["stop-at-empty-line"]:
                break
            continue

        # check for line continuations
        if line[0] in [' ', '\t', "+"]:
            line = line[1:]
            if not pragmas["whitespace-preserve"]:
                line = line.strip()
            entry = result.pop()
            value = ({
                "cr": "\r",
                "lf": "\n",
                "crlf": "\r\n",
                "none": ""
            }[pragmas["newline-type"]]).join([entry[1], line])
            result.append((entry[0], value))
            continue

        try:
            key, value = line.split(":", 1)
        except ValueError:
            raise ValueError("Syntax error: Missing value")

        if pragmas["strict-ripe"]:
            if not re.match("^[a-zA-Z0-9-]+$", key):
                raise ValueError("Syntax error: Key doesn't match RIPE database requirements")

        if not pragmas["whitespace-preserve"]:
            key = key.strip()
            value = value.strip()

        if pragmas["condense-whitespace"]:
            import re
            value = re.sub(r"[\s]+", " ", value, flags=re.M|re.S)

        result.append((key, value))

    return result

if __name__ == "__main__":
    import argparse
    import sys

    argparser = argparse.ArgumentParser(description="Pretty-print objects")
    argparser.add_argument("--min-padding", help="Minimal padding between key and value", type=int, default=0)
    argparser.add_argument("--add-padding", help="Additional padding between key and value", type=int, default=8)
    argparser.add_argument("files", nargs='*', help="Input files")

    args = argparser.parse_args()

    options = dict(
            min_padding=args.min_padding,
            add_padding=args.add_padding)

    if not args.files:
        obj = Object.from_file(sys.stdin)
        print("".join(obj.pretty_print(**options)))
    else:
        for f in args.files:
            with open(f) as fh:
                obj = Object.from_file(fh)
                print("".join(obj.pretty_print(**options)))

<|endoftext|>