nodes: 0, module; 1, function_definition; 2, function_name:find_files; 3, parameters; 4, block; 5, default_parameter; 6, default_parameter; 7, default_parameter; 8, default_parameter; 9, default_parameter; 10, default_parameter; 11, default_parameter; 12, expression_statement; 13, expression_statement; 14, if_statement; 15, identifier:path; 16, string; 17, identifier:ext; 18, string; 19, identifier:level; 20, None; 21, identifier:typ; 22, identifier:list; 23, identifier:dirs; 24, False; 25, identifier:files; 26, True; 27, identifier:verbosity; 28, integer:0; 29, comment:""" Recursively find all files in the indicated directory
  
      Filter by the indicated file name extension (ext)
  
      Args:
        path (str):  Root/base path to search.
        ext (str):   File name extension. Only file paths that ".endswith()" this string will be returned
        level (int, optional): Depth of file tree to halt recursion at.
          None = full recursion to as deep as it goes
          0 = nonrecursive, just provide a list of files at the root level of the tree
          1 = one level of depth deeper in the tree
        typ (type):  output type (default: list). if a mapping type is provided the keys will be the full paths (unique)
        dirs (bool):  Whether to yield dir paths along with file paths (default: False)
        files (bool): Whether to yield file paths (default: True)
          `dirs=True`, `files=False` is equivalent to `ls -d`
  
      Returns:
        list of dicts: dict keys are { 'path', 'name', 'bytes', 'created', 'modified', 'accessed', 'permissions' }
          path (str): Full, absolute paths to file beneath the indicated directory and ending with `ext`
          name (str): File name only (everythin after the last slash in the path)
          size (int): File size in bytes
          created (datetime): File creation timestamp from file system
          modified (datetime): File modification timestamp from file system
          accessed (datetime): File access timestamp from file system
          permissions (int): File permissions bytes as a chown-style integer with a maximum of 4 digits
          type (str): One of 'file', 'dir', 'symlink->file', 'symlink->dir', 'symlink->broken'
            e.g.: 777 or 1755
  
      Examples:
        >>> 'util.py' in [d['name'] for d in find_files(os.path.dirname(__file__), ext='.py', level=0)]
        True
        >>> (d for d in find_files(os.path.dirname(__file__), ext='.py') if d['name'] == 'util.py').next()['size'] > 1000
        True
  
        There should be an __init__ file in the same directory as this script.
        And it should be at the top of the list.
        >>> sorted(d['name'] for d in find_files(os.path.dirname(__file__), ext='.py', level=0))[0]
        '__init__.py'
        >>> all(d['type'] in ('file','dir','symlink->file','symlink->dir','mount-point->file','mount-point->dir','block-device',
                              'symlink->broken','pipe','special','socket','unknown') for d in find_files(level=1, files=True, dirs=True))
        True
        >>> os.path.join(os.path.dirname(__file__), '__init__.py') in find_files(
        ... os.path.dirname(__file__), ext='.py', level=0, typ=dict)
        True
      """; 30, assignment; 31, call; 32, block; 33, elif_clause; 34, else_clause; 35, identifier:gen; 36, call; 37, identifier:isinstance; 38, argument_list; 39, return_statement; 40, comparison_operator:typ is not None; 41, block; 42, block; 43, identifier:generate_files; 44, argument_list; 45, call; 46, attribute; 47, call; 48, identifier:typ; 49, None; 50, return_statement; 51, return_statement; 52, identifier:path; 53, keyword_argument; 54, keyword_argument; 55, keyword_argument; 56, keyword_argument; 57, keyword_argument; 58, identifier:typ; 59, argument_list; 60, identifier:collections; 61, identifier:Mapping; 62, identifier:typ; 63, generator_expression; 64, call; 65, identifier:gen; 66, identifier:ext; 67, identifier:ext; 68, identifier:level; 69, identifier:level; 70, identifier:dirs; 71, identifier:dirs; 72, identifier:files; 73, identifier:files; 74, identifier:verbosity; 75, identifier:verbosity; 76, tuple; 77, for_in_clause; 78, identifier:typ; 79, argument_list; 80, subscript; 81, identifier:ff; 82, identifier:ff; 83, identifier:gen; 84, identifier:gen; 85, identifier:ff; 86, string; 87, string_content:path
code: def find_files(path='', ext='', level=None, typ=list, dirs=False, files=True, verbosity=0):
      """ Recursively find all files in the indicated directory
  
      Filter by the indicated file name extension (ext)
  
      Args:
        path (str):  Root/base path to search.
        ext (str):   File name extension. Only file paths that ".endswith()" this string will be returned
        level (int, optional): Depth of file tree to halt recursion at.
          None = full recursion to as deep as it goes
          0 = nonrecursive, just provide a list of files at the root level of the tree
          1 = one level of depth deeper in the tree
        typ (type):  output type (default: list). if a mapping type is provided the keys will be the full paths (unique)
        dirs (bool):  Whether to yield dir paths along with file paths (default: False)
        files (bool): Whether to yield file paths (default: True)
          `dirs=True`, `files=False` is equivalent to `ls -d`
  
      Returns:
        list of dicts: dict keys are { 'path', 'name', 'bytes', 'created', 'modified', 'accessed', 'permissions' }
          path (str): Full, absolute paths to file beneath the indicated directory and ending with `ext`
          name (str): File name only (everythin after the last slash in the path)
          size (int): File size in bytes
          created (datetime): File creation timestamp from file system
          modified (datetime): File modification timestamp from file system
          accessed (datetime): File access timestamp from file system
          permissions (int): File permissions bytes as a chown-style integer with a maximum of 4 digits
          type (str): One of 'file', 'dir', 'symlink->file', 'symlink->dir', 'symlink->broken'
            e.g.: 777 or 1755
  
      Examples:
        >>> 'util.py' in [d['name'] for d in find_files(os.path.dirname(__file__), ext='.py', level=0)]
        True
        >>> (d for d in find_files(os.path.dirname(__file__), ext='.py') if d['name'] == 'util.py').next()['size'] > 1000
        True
  
        There should be an __init__ file in the same directory as this script.
        And it should be at the top of the list.
        >>> sorted(d['name'] for d in find_files(os.path.dirname(__file__), ext='.py', level=0))[0]
        '__init__.py'
        >>> all(d['type'] in ('file','dir','symlink->file','symlink->dir','mount-point->file','mount-point->dir','block-device',
                              'symlink->broken','pipe','special','socket','unknown') for d in find_files(level=1, files=True, dirs=True))
        True
        >>> os.path.join(os.path.dirname(__file__), '__init__.py') in find_files(
        ... os.path.dirname(__file__), ext='.py', level=0, typ=dict)
        True
      """
      gen = generate_files(path, ext=ext, level=level, dirs=dirs, files=files, verbosity=verbosity)
      if isinstance(typ(), collections.Mapping):
          return typ((ff['path'], ff) for ff in gen)
      elif typ is not None:
          return typ(gen)
      else:
          return gen