Source code for glotter_core.source

"""Source information"""

import os
from dataclasses import dataclass, field
from pathlib import Path

import yaml

from glotter_core.project import CoreProjectMixin, NamingScheme
from glotter_core.testinfo import TestInfo


[docs] @dataclass(frozen=True) class CoreSource: """Metadata about a source file :param filename: filename including extension :param language: the language of the source :param path: path to the file excluding name :param str test_info: a string in yaml format containing testinfo for a directory :param project_type: name of project for this source :ivar filename: filename including extension :ivar language: the language of the source :ivar path: path to the file excluding name :ivar TestInfo test_info: TestInfo object :param project_type: name of project for this source """ filename: str language: str path: str test_info: str = field(repr=False) project_type: str def __post_init__(self) -> None: object.__setattr__(self, "test_info", TestInfo.from_string(self.test_info, self)) @property def full_path(self) -> str: """Returns the full path to the source including filename and extension""" return str(Path(self.path) / self.filename) @property def name(self) -> str: """Returns the name of the source excluding the extension""" return self.filename.split(".")[0] @property def extension(self) -> str: """Returns the extension of the source""" return "".join(Path(self.filename).suffixes)
[docs] @dataclass class CoreLanguage: """ Information about a language :ivar sources: list of source objects :ivar test_info: TestInfo object :ivar path: Path to TestInfo object file """ sources: list[CoreSource] test_info: TestInfo test_info_path: Path
[docs] @dataclass class CoreSourceCategories: """ Categories for sources :ivar testable_by_project: dictionary whose key is the project type and whose value is a list of testable source object :ivar by_language: dictionary whose key is the language and whose value is a CoreLanguage object :ivar bad_sources: list of filenames that do not belong to a project """ testable_by_project: dict[str, list[CoreSource]] = field(default_factory=dict) by_language: dict[str, list[CoreLanguage]] = field(default_factory=dict) bad_sources: list[str] = field(default_factory=list)
_IGNORED_FILENAMES = {"untestable.yml", "testinfo.yml", "README.md"}
[docs] def categorize_sources( path: str, projects: dict[str, CoreProjectMixin], source_cls: type ) -> CoreSourceCategories: """ Categorize sources :param path: path to source directory :param projects: dictionary whose key is a project type and whose value is a CoreProjectMixin object :param source_cls: source object class :return: CoreSourceCategories object containing information of the source categories """ categories = CoreSourceCategories() categories.testable_by_project = {k: [] for k in projects} orig_path = Path(path).resolve() for root, _, files in os.walk(path): current_path = Path(root).resolve() test_info_string = "" test_info_filename = "" if "testinfo.yml" in files: test_info_filename = "testinfo.yml" test_info_string = Path(current_path, test_info_filename).read_text(encoding="utf-8") elif "untestable.yml" in files: test_info_filename = "untestable.yml" test_info_string = _convert_untestable_to_testinfo(current_path, files, projects) if test_info_string: language = current_path.name test_info = TestInfo.from_dict(yaml.safe_load(test_info_string), language) folder_info = test_info.file_info folder_project_names = folder_info.get_project_mappings( projects, include_extension=True ) sources = [] test_info_path = Path(current_path, test_info_filename) for project_type, project_name in folder_project_names.items(): if project_name in files: source = source_cls( filename=project_name, language=language, path=str(current_path), test_info=test_info_string, project_type=project_type, ) sources.append(source) if source.test_info.is_testable: categories.testable_by_project[project_type].append(source) categories.by_language[language] = CoreLanguage(sources, test_info, test_info_path) invalid_filenames = set(files) - ( set(folder_project_names.values()) | _IGNORED_FILENAMES ) categories.bad_sources += [ str(current_path.relative_to(orig_path) / filename) for filename in invalid_filenames ] return categories
def _convert_untestable_to_testinfo( current_path: Path, files: list[str], projects: dict[str, CoreProjectMixin] ) -> str: with Path(current_path, "untestable.yml").open(encoding="utf-8") as f: untestable_data = yaml.safe_load(f) notes = untestable_data[0]["reason"] for filename in files: if filename in _IGNORED_FILENAMES: continue base_filename = filename.split(".")[0] extension = "".join(Path(filename).suffixes) project_type = base_filename.lower().replace("-", "").replace("_", "") if project_type in projects and len(projects[project_type].words) > 1: for naming_scheme in NamingScheme: expected_filename = ( projects[project_type].get_project_name_by_scheme(naming_scheme) + extension ) if filename == expected_filename: test_info_dict = { "folder": { "extension": extension, "naming": naming_scheme.value, }, "notes": [notes], } return yaml.dump(test_info_dict, sort_keys=False) return "" __all__ = ["CoreLanguage", "CoreSource", "CoreSourceCategories", "categorize_sources"]