Source code for projectreport.analyzer.folder

from pathlib import Path
from typing import TYPE_CHECKING, List, Optional, Sequence, Union

from projectreport.analyzer.parsers.github import GithubParser
from projectreport.analyzer.parsers.multi.file import MultiFileParser
from projectreport.analyzer.parsers.multi.main import MainMultiParser
from projectreport.logger import logger

if TYPE_CHECKING:
    from projectreport.analyzer.project import Project
    from projectreport.analyzer.parsers.base import Parser

import os

from cached_property import cached_property

from projectreport.analyzer.analysis import FolderAnalysis
from projectreport.analyzer.analyzable import Analyzable
from projectreport.analyzer.module import Module
from projectreport.analyzer.parsers.index import PARSER_DOC_FILES
from projectreport.config import DEFAULT_IGNORE_PATHS
from projectreport.tools.expand_glob import all_possible_paths


[docs]class Folder(Analyzable):
[docs] def __init__( self, path: Union[str, Path], project: Optional["Project"] = None, excluded_types: Optional[Sequence[str]] = None, included_types: Optional[Sequence[str]] = None, ignore_paths: Optional[Sequence[str]] = DEFAULT_IGNORE_PATHS, ): from projectreport.analyzer.project import Project path = os.path.abspath(path) self.name = os.path.basename(path) self.options = dict( excluded_types=excluded_types, included_types=included_types, ignore_paths=ignore_paths, ) if project is None: project = Project(self.path, **self.options) self._validate() super().__init__(path, project=project)
@cached_property def file_names(self) -> List[str]: file_names = [file for file in next(os.walk(self.path))[2]] return file_names @cached_property def file_paths(self) -> List[str]: included_files = [] if self.options["ignore_paths"] is not None: all_ignore_paths = all_possible_paths( self.options["ignore_paths"], self.path ) for file in self.file_names: if self.options["ignore_paths"]: file_path = os.path.join(self.path, file) if file_path in all_ignore_paths: continue # this file excluded, skip it extension = os.path.splitext(file)[1].strip(".") if self.options["included_types"] is not None: if extension in self.options["included_types"]: included_files.append(file) elif self.options["excluded_types"] is not None: if extension not in self.options["excluded_types"]: included_files.append(file) else: # No included or excluded files, just keep all included_files.append(file) files = [os.path.join(self.path, name) for name in included_files] return files @cached_property def folder_paths(self) -> List[str]: folders = [file for file in next(os.walk(self.path))[1]] if self.options["ignore_paths"] is not None: all_ignore_paths = all_possible_paths( self.options["ignore_paths"], self.path ) out_folders = [] for folder in folders: abs_folder = os.path.join(self.path, folder) if self.options["ignore_paths"] is not None: if abs_folder in all_ignore_paths: continue # this folder excluded, skip it out_folders.append(abs_folder) return out_folders @cached_property def modules(self) -> List["Module"]: return [ Module(file_path, self.name, project=self.project) for file_path in self.file_paths ] @cached_property def folders(self) -> List["Folder"]: all_folders = [ Folder(folder, project=self.project, **self.options) for folder in self.folder_paths ] non_empty_folders = [folder for folder in all_folders if not folder.is_empty] return non_empty_folders @cached_property def analysis(self) -> "FolderAnalysis": analysis = FolderAnalysis(self) for folder in self.folders: logger.debug(f"Analyzing folder {folder.name}") analysis.add_subfolder_analysis(folder.analysis) for module in self.modules: logger.debug(f"Analyzing module {module.name}") analysis.add_module_analysis(module.analysis) return analysis @cached_property def parser(self) -> Optional["Parser"]: if not MainMultiParser.matches_path( self.path, self.file_names, self.analysis.data.get("urls") ): return None return MainMultiParser( self.path, self.file_names, self.analysis.data.get("urls") ) @cached_property def is_empty(self) -> bool: len_contents = len(self.file_paths) + len(self.folders) return len_contents == 0 def _validate(self): if self.options["included_types"] and self.options["excluded_types"]: raise ValueError("cannot pass both include and exclude types")