Example #1
0
 def __iter__(self):
     """List available virtual environments found in $VIRTUALENV_HOME.
     """
     # FIXME: Handle subdirs--this won't discover eg ``spam/eggs``
     for x in scandir(self.venvdir):
         if x.is_dir():
             yield x.name
Example #2
0
def test_news():
    newsdir = os.path.join(os.path.dirname(
                           os.path.dirname(__file__)), 'news')
    for f in scandir(newsdir):
        base, ext = os.path.splitext(f.path)
        assert '.rst' == ext
        yield check_news_file, f.path
Example #3
0
 def __iter__(self):
     """List available virtual environments found in $VIRTUALENV_HOME.
     """
     # FIXME: Handle subdirs--this won't discover eg ``spam/eggs``
     for x in scandir(self.venvdir):
         if x.is_dir():
             yield x.name
Example #4
0
def _yield_accessible_unix_file_names(path):
    "yield file names of executablel files in `path`"

    for file_ in scandir(path):
        try:
            if file_.is_file() and os.access(file_.path, os.X_OK):
                yield file_.name
        except NotADirectoryError:
            # broken Symlink are neither dir not files
            pass
Example #5
0
def _yield_accessible_unix_file_names(path):
    "yield file names of executablel files in `path`"

    for file_ in scandir(path):
        try:
            if file_.is_file() and os.access(file_.path, os.X_OK):
                yield file_.name
        except NotADirectoryError:
            # broken Symlink are neither dir not files
            pass
Example #6
0
def _executables_in_posix(path):
    if PYTHON_VERSION_INFO < (3, 5, 0):
        for fname in os.listdir(path):
            fpath  = os.path.join(path, fname)
            if (os.path.exists(fpath) and os.access(fpath, os.X_OK) and \
                                    (not os.path.isdir(fpath))):
                yield fname
    else:
        yield from (x.name for x in scandir(path)
                    if x.is_file() and os.access(x.path, os.X_OK))
Example #7
0
File: tools.py Project: a-da/xonsh
def _yield_accessible_unix_file_names(path):
    """yield file names of executable files in path."""
    if not os.path.exists(path):
        return
    for file_ in scandir(path):
        try:
            if file_.is_file() and os.access(file_.path, os.X_OK):
                yield file_.name
        except (FileNotFoundError, NotADirectoryError):
            # broken Symlink are neither dir not files
            pass
Example #8
0
def _yield_accessible_unix_file_names(path):
    """yield file names of executable files in path."""
    if not os.path.exists(path):
        return
    for file_ in scandir(path):
        try:
            if file_.is_file() and os.access(file_.path, os.X_OK):
                yield file_.name
        except (FileNotFoundError, NotADirectoryError):
            # broken Symlink are neither dir not files
            pass
Example #9
0
def executables_in(path):
    """Returns a generator of files in `path` that the user could execute. """
    try:
        if PYTHON_VERSION_INFO < (3, 5, 0):
            for i in os.listdir(path):
                name  = os.path.join(path, i)
                if (os.path.exists(name) and os.access(name, os.X_OK) and \
                                        (not os.path.isdir(name))):
                    yield i
        else:
            yield from (x.name for x in scandir(path)
                        if x.is_file() and os.access(x.path, os.X_OK))
    except PermissionError:
        return
Example #10
0
def print_path(abs_name, from_where, stdout, verbose=False):
    """Print the name and path of the command."""
    if xp.ON_WINDOWS:
        # Use list dir to get correct case for the filename
        # i.e. windows is case insensitive but case preserving
        p, f = os.path.split(abs_name)
        f = next(s.name for s in xp.scandir(p) if s.name.lower() == f.lower())
        abs_name = os.path.join(p, f)
        if builtins.__xonsh_env__.get('FORCE_POSIX_PATHS', False):
            abs_name.replace(os.sep, os.altsep)
    if not verbose:
        print(abs_name, file=stdout)
    else:
        print('{} ({})'.format(abs_name, from_where), file=stdout)
Example #11
0
def _executables_in_windows(path):
    extensions = builtins.__xonsh_env__.get('PATHEXT',['.COM', '.EXE', '.BAT'])
    if PYTHON_VERSION_INFO < (3, 5, 0):
        for fname in os.listdir(path):
            fpath = os.path.join(path, fname)
            if (os.path.exists(fpath) and not os.path.isdir(fpath)):
                base_name, ext = os.path.splitext(fname)
                if ext.upper() in extensions:
                    yield fname
    else:
        for fname in (x.name for x in scandir(path) if x.is_file()):
            base_name, ext = os.path.splitext(fname)
            if ext.upper() in extensions:
                yield fname
Example #12
0
def _executables_in_windows(path):
    extensions = builtins.__xonsh_env__.get('PATHEXT',
                                            ['.COM', '.EXE', '.BAT'])
    if PYTHON_VERSION_INFO < (3, 5, 0):
        for fname in os.listdir(path):
            fpath = os.path.join(path, fname)
            if (os.path.exists(fpath) and not os.path.isdir(fpath)):
                base_name, ext = os.path.splitext(fname)
                if ext.upper() in extensions:
                    yield fname
    else:
        for fname in (x.name for x in scandir(path) if x.is_file()):
            base_name, ext = os.path.splitext(fname)
            if ext.upper() in extensions:
                yield fname
Example #13
0
def print_path(abs_name, from_where, stdout, verbose=False, captured=False):
    """Print the name and path of the command."""
    if xp.ON_WINDOWS:
        # Use list dir to get correct case for the filename
        # i.e. windows is case insensitive but case preserving
        p, f = os.path.split(abs_name)
        f = next(s.name for s in xp.scandir(p) if s.name.lower() == f.lower())
        abs_name = os.path.join(p, f)
        if builtins.__xonsh__.env.get("FORCE_POSIX_PATHS", False):
            abs_name.replace(os.sep, os.altsep)
    if verbose:
        print(f"{abs_name} ({from_where})", file=stdout)
    else:
        end = "" if captured else "\n"
        print(abs_name, end=end, file=stdout)
Example #14
0
    def list_envs():
        """List available virtual environments."""

        venv_home = builtins.__xonsh_env__['VIRTUALENV_HOME']
        try:
            env_dirs = list(x.name for x in scandir(venv_home) if x.is_dir())
        except PermissionError:
            print('No permissions on {}'.format(venv_home))
            return None

        if not env_dirs:
            print('No environments available. Create one with "vox new".\n')
            return None

        print('Available environments:')
        print('\n'.join(env_dirs))
Example #15
0
File: vox.py Project: zbrdge/xonsh
    def list_envs():
        """List available virtual environments."""

        venv_home = builtins.__xonsh_env__['VIRTUALENV_HOME']
        try:
            env_dirs = list(x.name for x in scandir(venv_home) if x.is_dir())
        except PermissionError:
            print('No permissions on {}'.format(venv_home))
            return None

        if not env_dirs:
            print('No environments available. Create one with "vox new".\n')
            return None

        print('Available environments:')
        print('\n'.join(env_dirs))
Example #16
0
def _executables_in_windows(path):
    if not os.path.isdir(path):
        return
    extensions = builtins.__xonsh_env__['PATHEXT']
    if PYTHON_VERSION_INFO < (3, 5, 0):
        for fname in os.listdir(path):
            fpath = os.path.join(path, fname)
            if (os.path.exists(fpath) and not os.path.isdir(fpath)):
                base_name, ext = os.path.splitext(fname)
                if ext.upper() in extensions:
                    yield fname
    else:
        for x in scandir(path):
            if x.is_file():
                fname = x.name
            else:
                continue
            base_name, ext = os.path.splitext(fname)
            if ext.upper() in extensions:
                yield fname
Example #17
0
File: tools.py Project: a-da/xonsh
def _executables_in_windows(path):
    if not os.path.isdir(path):
        return
    extensions = builtins.__xonsh_env__['PATHEXT']
    if PYTHON_VERSION_INFO < (3, 5, 0):
        for fname in os.listdir(path):
            fpath = os.path.join(path, fname)
            if (os.path.exists(fpath) and not os.path.isdir(fpath)):
                base_name, ext = os.path.splitext(fname)
                if ext.upper() in extensions:
                    yield fname
    else:
        for x in scandir(path):
            if x.is_file():
                fname = x.name
            else:
                continue
            base_name, ext = os.path.splitext(fname)
            if ext.upper() in extensions:
                yield fname
Example #18
0
 def find_spec(self, fullname, path, target=None):
     """Finds the spec for a xonsh module if it exists."""
     dot = '.'
     spec = None
     path = sys.path if path is None else path
     if dot not in fullname and dot not in path:
         path = [dot] + path
     name = fullname.rsplit(dot, 1)[-1]
     fname = name + '.xsh'
     for p in path:
         if not isinstance(p, str):
             continue
         if not os.path.isdir(p) or not os.access(p, os.R_OK):
             continue
         if fname not in (x.name for x in scandir(p)):
             continue
         spec = ModuleSpec(fullname, self)
         self._filenames[fullname] = os.path.join(p, fname)
         break
     return spec
Example #19
0
            cat = l[2:].rsplit(':')[0]
            if cat not in CATEGORIES:
                pytest.fail('{}:{}: {!r} not a proper category '
                            'must be one of {}'
                            ''.format(name, i + 1, cat, list(CATEGORIES)),
                            pytrace=False)
            if l.endswith('None'):
                form += '3'
            else:
                form += '2'
        elif l.startswith('* ') or l.startswith('- ') or l.startswith('  '):
            form += '1'
        elif l.strip() == '':
            form += '0'
        else:
            pytest.fail('{}:{}: invalid rst'.format(name, i + 1),
                        pytrace=False)
    # The file should have:
    #   empty lines around categories
    #   at least one content line in a non null category
    reg = re.compile(r'^(3(0|$)|201(1|0)*0)+$')
    if not reg.match(form):
        pytest.fail('{}: invalid rst'.format(name), pytrace=False)


@pytest.mark.parametrize('fname', list(scandir(NEWSDIR)))
def test_news(fname):
    base, ext = os.path.splitext(fname.path)
    assert 'rst' in ext
    check_news_file(fname)
Example #20
0
def which(args, stdin=None, stdout=None, stderr=None):
    """
    Checks if each arguments is a xonsh aliases, then if it's an executable,
    then finally return an error code equal to the number of misses.
    If '-a' flag is passed, run both to return both `xonsh` match and
    `which` match.
    """
    desc = "Parses arguments to which wrapper"
    parser = argparse.ArgumentParser('which', description=desc)
    parser.add_argument('args', type=str, nargs='+',
                        help='The executables or aliases to search for')
    parser.add_argument('-a','--all', action='store_true', dest='all',
                        help='Show all matches in $PATH and xonsh.aliases')
    parser.add_argument('-s', '--skip-alias', action='store_true',
                        help='Do not search in xonsh.aliases', dest='skip')
    parser.add_argument('-V', '--version', action='version',
                        version='{}'.format(_which.__version__),
                        help='Display the version of the python which module '
                        'used by xonsh')
    parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
                        help='Print out how matches were located and show '
                        'near misses on stderr')
    parser.add_argument('-p', '--plain', action='store_true', dest='plain',
                        help='Do not display alias expansions or location of '
                             'where binaries are found. This is the '
                             'default behavior, but the option can be used to '
                             'override the --verbose option')
    parser.add_argument('--very-small-rocks', action=AWitchAWitch)
    if ON_WINDOWS:
        parser.add_argument('-e', '--exts', nargs='*', type=str,
                            help='Specify a list of extensions to use instead '
                            'of the standard list for this system. This can '
                            'effectively be used as an optimization to, for '
                            'example, avoid stat\'s of "foo.vbs" when '
                            'searching for "foo" and you know it is not a '
                            'VisualBasic script but ".vbs" is on PATHEXT. '
                            'This option is only supported on Windows',
                            dest='exts')
    if len(args) == 0:
        parser.print_usage(file=stderr)
        return -1
    pargs = parser.parse_args(args)

    if pargs.all:
        pargs.verbose = True

    if ON_WINDOWS:
        if pargs.exts:
            exts = pargs.exts
        else:
            exts = builtins.__xonsh_env__['PATHEXT']
    else:
        exts = None

    failures = []
    for arg in pargs.args:
        nmatches = 0
        # skip alias check if user asks to skip
        if (arg in builtins.aliases and not pargs.skip):
            if pargs.plain or not pargs.verbose:
                if isinstance(builtins.aliases[arg], list):
                    print(' '.join(builtins.aliases[arg]), file=stdout)
                else:
                    print(arg, file=stdout)
            else:
                print("aliases['{}'] = {}".format(arg, builtins.aliases[arg]), file=stdout)
            nmatches += 1
            if not pargs.all:
                continue
        # which.whichgen gives the nicest 'verbose' output if PATH is taken
        # from os.environ so we temporarily override it with
        # __xosnh_env__['PATH']
        original_os_path = os.environ['PATH']
        os.environ['PATH'] = builtins.__xonsh_env__.detype()['PATH']
        matches = _which.whichgen(arg, exts=exts, verbose=pargs.verbose)
        for abs_name, from_where in matches:
            if ON_WINDOWS:
                # Use list dir to get correct case for the filename
                # i.e. windows is case insensitive but case preserving
                p, f = os.path.split(abs_name)
                f = next(s.name for s in scandir(p) if s.name.lower() == f.lower())
                abs_name = os.path.join(p, f)
                if builtins.__xonsh_env__.get('FORCE_POSIX_PATHS', False):
                    abs_name.replace(os.sep, os.altsep)
            if pargs.plain or not pargs.verbose:
                print(abs_name, file=stdout)
            else:
                print('{} ({})'.format(abs_name, from_where), file=stdout)
            nmatches += 1
            if not pargs.all:
                break
        os.environ['PATH'] = original_os_path
        if not nmatches:
            failures.append(arg)
    if len(failures) == 0:
        return 0
    else:
        print('{} not in $PATH'.format(', '.join(failures)), file=stderr, end='')
        if not pargs.skip:
            print(' or xonsh.builtins.aliases', file=stderr, end='')
        print('', end='\n')
        return len(failures)
Example #21
0
def which(args, stdin=None, stdout=None, stderr=None):
    """
    Checks if each arguments is a xonsh aliases, then if it's an executable,
    then finally return an error code equal to the number of misses.
    If '-a' flag is passed, run both to return both `xonsh` match and
    `which` match.
    """
    desc = "Parses arguments to which wrapper"
    parser = ArgumentParser("which", description=desc)
    parser.add_argument("args", type=str, nargs="+", help="The executables or aliases to search for")
    parser.add_argument(
        "-a", "--all", action="store_true", dest="all", help="Show all matches in $PATH and xonsh.aliases"
    )
    parser.add_argument("-s", "--skip-alias", action="store_true", help="Do not search in xonsh.aliases", dest="skip")
    parser.add_argument(
        "-V",
        "--version",
        action="version",
        version="{}".format(_which.__version__),
        help="Display the version of the python which module " "used by xonsh",
    )
    parser.add_argument(
        "-v",
        "--verbose",
        action="store_true",
        dest="verbose",
        help="Print out how matches were located and show " "near misses on stderr",
    )
    parser.add_argument(
        "-p",
        "--plain",
        action="store_true",
        dest="plain",
        help="Do not display alias expansions or location of "
        "where binaries are found. This is the "
        "default behavior, but the option can be used to "
        "override the --verbose option",
    )
    parser.add_argument("--very-small-rocks", action=AWitchAWitch)
    if ON_WINDOWS:
        parser.add_argument(
            "-e",
            "--exts",
            nargs="*",
            type=str,
            help="Specify a list of extensions to use instead "
            "of the standard list for this system. This can "
            "effectively be used as an optimization to, for "
            'example, avoid stat\'s of "foo.vbs" when '
            'searching for "foo" and you know it is not a '
            'VisualBasic script but ".vbs" is on PATHEXT. '
            "This option is only supported on Windows",
            dest="exts",
        )
    if len(args) == 0:
        parser.print_usage(file=stderr)
        return -1
    pargs = parser.parse_args(args)

    if pargs.all:
        pargs.verbose = True

    if ON_WINDOWS:
        if pargs.exts:
            exts = pargs.exts
        else:
            exts = builtins.__xonsh_env__.get("PATHEXT", [".COM", ".EXE", ".BAT"])
    else:
        exts = None

    failures = []
    for arg in pargs.args:
        nmatches = 0
        # skip alias check if user asks to skip
        if arg in builtins.aliases and not pargs.skip:
            if pargs.plain or not pargs.verbose:
                if isinstance(builtins.aliases[arg], list):
                    print(" ".join(builtins.aliases[arg]), file=stdout)
                else:
                    print(arg, file=stdout)
            else:
                print("aliases['{}'] = {}".format(arg, builtins.aliases[arg]), file=stdout)
            nmatches += 1
            if not pargs.all:
                continue
        # which.whichgen gives the nicest 'verbose' output if PATH is taken
        # from os.environ so we temporarily override it with
        # __xosnh_env__['PATH']
        original_os_path = os.environ["PATH"]
        os.environ["PATH"] = builtins.__xonsh_env__.detype()["PATH"]
        matches = _which.whichgen(arg, exts=exts, verbose=pargs.verbose)
        os.environ["PATH"] = original_os_path
        for abs_name, from_where in matches:
            if ON_WINDOWS:
                # Use list dir to get correct case for the filename
                # i.e. windows is case insensitive but case preserving
                p, f = os.path.split(abs_name)
                f = next(s.name for s in scandir(p) if s.name.lower() == f.lower())
                abs_name = os.path.join(p, f)
                if builtins.__xonsh_env__.get("FORCE_POSIX_PATHS", False):
                    abs_name.replace(os.sep, os.altsep)
            if pargs.plain or not pargs.verbose:
                print(abs_name, file=stdout)
            else:
                print("{} ({})".format(abs_name, from_where), file=stdout)
            nmatches += 1
            if not pargs.all:
                break
        if not nmatches:
            failures.append(arg)
    if len(failures) == 0:
        return 0
    else:
        print("{} not in $PATH".format(", ".join(failures)), file=stderr, end="")
        if not pargs.skip:
            print(" or xonsh.builtins.aliases", file=stderr, end="")
        print("", end="\n")
        return len(failures)
Example #22
0
            if cat not in CATEGORIES:
                pytest.fail(
                    "{}:{}: {!r} not a proper category "
                    "must be one of {}"
                    "".format(name, i + 1, cat, list(CATEGORIES)),
                    pytrace=False,
                )
            if l.endswith("None"):
                form += "3"
            else:
                form += "2"
        elif l.startswith("* ") or l.startswith("- ") or l.startswith("  "):
            form += "1"
        elif l.strip() == "":
            form += "0"
        else:
            pytest.fail("{}:{}: invalid rst".format(name, i + 1), pytrace=False)
    # The file should have:
    #   empty lines around categories
    #   at least one content line in a non null category
    reg = re.compile(r"^(3(0|$)|201(1|0)*0)+$")
    if not reg.match(form):
        pytest.fail("{}: invalid rst".format(name), pytrace=False)


@pytest.mark.parametrize("fname", list(scandir(NEWSDIR)))
def test_news(fname):
    base, ext = os.path.splitext(fname.path)
    assert "rst" in ext
    check_news_file(fname)
Example #23
0
def test_news():
    newsdir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'news')
    for f in scandir(newsdir):
        base, ext = os.path.splitext(f.path)
        assert '.rst' == ext
        yield check_news_file, f.path
Example #24
0
                            ''.format(name, i+1), pytrace=False)
            if i > 0 and not lines[i-1].strip() == '':
                pytest.fail('{}:{}: empty line required before category'
                            ''.format(name, i+1), pytrace=False)
            if line.endswith('None'):
                if not lines[i+2].startswith('**'):
                    pytest.fail("{}:{}: can't have entries after None"
                                ''.format(name, i+1), pytrace=False)
            else:
                if lines[i+2].startswith('**'):
                    pytest.fail("{}:{}: must have entry if not None"
                                ''.format(name, i+1), pytrace=False)
        else:
            if not (line.startswith('* ')
                    or line.startswith('  ')
                    or (line.strip() == '')):
                pytest.fail('{}:{}: invalid rst'.format(name, i+1),
                            pytrace=False)
            if '`' in line:
                if single_grave_reg.search(line):
                    pytest.fail("{}:{}: single grave accents"
                                " are not valid rst".format(name, i+1),
                                pytrace=False)


@pytest.mark.parametrize('fname', list(scandir(NEWSDIR)))
def test_news(fname):
    base, ext = os.path.splitext(fname.path)
    assert 'rst' in ext
    check_news_file(fname)
Example #25
0
def which(args, stdin=None, stdout=None, stderr=None):
    """
    Checks if each arguments is a xonsh aliases, then if it's an executable,
    then finally return an error code equal to the number of misses.
    If '-a' flag is passed, run both to return both `xonsh` match and
    `which` match.
    """
    desc = "Parses arguments to which wrapper"
    parser = ArgumentParser('which', description=desc)
    parser.add_argument('args', type=str, nargs='+',
                        help='The executables or aliases to search for')
    parser.add_argument('-a','--all', action='store_true', dest='all',
                        help='Show all matches in $PATH and xonsh.aliases')
    parser.add_argument('-s', '--skip-alias', action='store_true',
                        help='Do not search in xonsh.aliases', dest='skip')
    parser.add_argument('-V', '--version', action='version',
                        version='{}'.format(_which.__version__),
                        help='Display the version of the python which module '
                        'used by xonsh')
    parser.add_argument('-v', '--verbose', action='store_true', dest='verbose',
                        help='Print out how matches were located and show '
                        'near misses on stderr')
    parser.add_argument('-p', '--plain', action='store_true', dest='plain',
                        help='Do not display alias expansions or location of '
                             'where binaries are found. This is the '
                             'default behavior, but the option can be used to '
                             'override the --verbose option')
    parser.add_argument('--very-small-rocks', action=AWitchAWitch)
    if ON_WINDOWS:
        parser.add_argument('-e', '--exts', nargs='*', type=str,
                            help='Specify a list of extensions to use instead '
                            'of the standard list for this system. This can '
                            'effectively be used as an optimization to, for '
                            'example, avoid stat\'s of "foo.vbs" when '
                            'searching for "foo" and you know it is not a '
                            'VisualBasic script but ".vbs" is on PATHEXT. '
                            'This option is only supported on Windows',
                            dest='exts')
    if len(args) == 0:
        parser.print_usage(file=stderr)
        return -1
    pargs = parser.parse_args(args)

    if pargs.all:
        pargs.verbose = True

    if ON_WINDOWS:
        if pargs.exts:
            exts = pargs.exts
        else:
            exts = builtins.__xonsh_env__['PATHEXT']
    else:
        exts = None

    failures = []
    for arg in pargs.args:
        nmatches = 0
        # skip alias check if user asks to skip
        if (arg in builtins.aliases and not pargs.skip):
            if pargs.plain or not pargs.verbose:
                if isinstance(builtins.aliases[arg], list):
                    print(' '.join(builtins.aliases[arg]), file=stdout)
                else:
                    print(arg, file=stdout)
            else:
                print("aliases['{}'] = {}".format(arg, builtins.aliases[arg]), file=stdout)
            nmatches += 1
            if not pargs.all:
                continue
        # which.whichgen gives the nicest 'verbose' output if PATH is taken
        # from os.environ so we temporarily override it with
        # __xosnh_env__['PATH']
        original_os_path = os.environ['PATH']
        os.environ['PATH'] = builtins.__xonsh_env__.detype()['PATH']
        matches = _which.whichgen(arg, exts=exts, verbose=pargs.verbose)
        for abs_name, from_where in matches:
            if ON_WINDOWS:
                # Use list dir to get correct case for the filename
                # i.e. windows is case insensitive but case preserving
                p, f = os.path.split(abs_name)
                f = next(s.name for s in scandir(p) if s.name.lower() == f.lower())
                abs_name = os.path.join(p, f)
                if builtins.__xonsh_env__.get('FORCE_POSIX_PATHS', False):
                    abs_name.replace(os.sep, os.altsep)
            if pargs.plain or not pargs.verbose:
                print(abs_name, file=stdout)
            else:
                print('{} ({})'.format(abs_name, from_where), file=stdout)
            nmatches += 1
            if not pargs.all:
                break
        os.environ['PATH'] = original_os_path
        if not nmatches:
            failures.append(arg)
    if len(failures) == 0:
        return 0
    else:
        print('{} not in $PATH'.format(', '.join(failures)), file=stderr, end='')
        if not pargs.skip:
            print(' or xonsh.builtins.aliases', file=stderr, end='')
        print('', end='\n')
        return len(failures)
Example #26
0
                    "must be one of {}"
                    "".format(name, i + 1, cat, list(CATEGORIES)),
                    pytrace=True,
                )
            if l.endswith("None"):
                form += "3"
            else:
                form += "2"
        elif l.startswith("* <news item>"):
            form += "4"
        elif l.startswith("* ") or l.startswith("- ") or l.startswith("  "):
            form += "1"
        elif l.strip() == "":
            form += "0"
        else:
            pytest.fail("{}:{}: invalid rst".format(name, i + 1), pytrace=True)
    # The file should have:
    #   empty lines around categories
    #   at least one content line in a non null category
    reg = re.compile(r"^(3(0|$)|20(1|4)(1|0|4)*0|204$)+$")
    if not reg.match(form):
        print(form)
        pytest.fail("{}: invalid rst".format(name), pytrace=True)


@pytest.mark.parametrize("fname", list(scandir(NEWSDIR)))
def test_news(fname):
    base, ext = os.path.splitext(fname.path)
    assert "rst" in ext
    check_news_file(fname)