diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2de99c3..65333eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,23 +5,33 @@ on: release: types: published schedule: - - cron: 0 0 1 * * # Run once every month + - cron: 0 0 1 * * # Run once every month jobs: run-pytest: strategy: fail-fast: false matrix: - py: ['3.8', '3.9', '3.10', '3.11', '3.12'] - os: ['ubuntu-latest', 'windows-latest', 'macos-latest'] + py: [ '3.9', '3.10', '3.11', '3.12' ] + os: [ 'ubuntu-latest', 'windows-latest', 'macos-latest' ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.py }} - - name: "Install requirements" - run: | - python -m pip install -r requirements-dev.txt - - name: "Run pytest" - run: | - pytest + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.py }} + - name: "Install requirements" + run: | + python -m pip install -r requirements-dev.txt + - name: "Run pytest" + run: | + pytest + + check-typing: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + - run: pip install mypy + - run: mypy --install-types --non-interactive diff --git a/.gitignore b/.gitignore index a7edc71..dfdbb0e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ /build/ /.eggs/ /venv/ +/.venv *.egg-info *.py[co] diff --git a/cmake_file_api/__init__.py b/cmake_file_api/__init__.py index a9bcfc1..1aa5190 100644 --- a/cmake_file_api/__init__.py +++ b/cmake_file_api/__init__.py @@ -1,3 +1,5 @@ from .cmake import CMakeProject from .errors import CMakeException from .kinds.kind import ObjectKind + +__all__ = ["CMakeProject", "CMakeException", "ObjectKind"] diff --git a/cmake_file_api/cmake.py b/cmake_file_api/cmake.py index 610ae9a..c9af208 100644 --- a/cmake_file_api/cmake.py +++ b/cmake_file_api/cmake.py @@ -1,13 +1,14 @@ from pathlib import Path import subprocess -from typing import List, Optional, Union +from typing import Optional, Union from .reply.api import REPLY_API +from .reply.v1.api import CMakeFileApiV1 PathLike = Union[Path, str] -class CMakeProject(object): +class CMakeProject: __slots__ = ("_source_path", "_build_path", "_api_version", "_cmake") def __init__(self, build_path: PathLike, source_path: Optional[PathLike]=None, api_version: Optional[int]=None, cmake: Optional[str]=None): @@ -57,14 +58,14 @@ def _cache_lookup(name: str, cache: PathLike) -> str: _, value = line.split("=", 1) return value - def configure(self, args: Optional[List[str]]=None, quiet=False): + def configure(self, args: Optional[list[str]]=None, quiet: bool = False) -> None: if self._source_path is None: raise ValueError("Cannot configure with no source path") stdout = subprocess.DEVNULL if quiet else None args = [str(self._cmake), str(self._source_path)] + (args if args else []) subprocess.check_call(args, cwd=str(self._build_path), stdout=stdout) - def reconfigure(self, quiet=False): + def reconfigure(self, quiet: bool = False) -> None: stdout = subprocess.DEVNULL if quiet else None args = [str(self._cmake)] if self._source_path: @@ -74,5 +75,5 @@ def reconfigure(self, quiet=False): subprocess.check_call(args, cwd=str(self._build_path), stdout=stdout) @property - def cmake_file_api(self): + def cmake_file_api(self) -> CMakeFileApiV1: return REPLY_API[self._api_version](self._build_path) diff --git a/cmake_file_api/kinds/api.py b/cmake_file_api/kinds/api.py index aa60370..9346f6b 100644 --- a/cmake_file_api/kinds/api.py +++ b/cmake_file_api/kinds/api.py @@ -1,3 +1,7 @@ +from pathlib import Path +from typing import Protocol +from typing_extensions import Self + from .kind import ObjectKind from .cache.api import CACHE_API from .cmakeFiles.api import CMAKEFILES_API @@ -6,7 +10,14 @@ from .toolchains.api import TOOLCHAINS_API -OBJECT_KINDS_API = { +class CMakeApiType(Protocol): + KIND: ObjectKind + + @classmethod + def from_path(cls, path: Path, reply_path: Path) -> Self: + ... + +OBJECT_KINDS_API: dict[ObjectKind, dict[int, CMakeApiType]] = { ObjectKind.CACHE: CACHE_API, ObjectKind.CMAKEFILES: CMAKEFILES_API, ObjectKind.CONFIGURELOG: CONFIGURELOG_API, diff --git a/cmake_file_api/kinds/cache/__init__.py b/cmake_file_api/kinds/cache/__init__.py index 16a6596..9a24926 100644 --- a/cmake_file_api/kinds/cache/__init__.py +++ b/cmake_file_api/kinds/cache/__init__.py @@ -1 +1,3 @@ from .api import CACHE_API + +__all__ = ["CACHE_API"] diff --git a/cmake_file_api/kinds/cache/api.py b/cmake_file_api/kinds/cache/api.py index 5d872d8..863faac 100644 --- a/cmake_file_api/kinds/cache/api.py +++ b/cmake_file_api/kinds/cache/api.py @@ -1,6 +1,11 @@ +from __future__ import annotations +import typing + from .v2 import CacheV2 +if typing.TYPE_CHECKING: + from ..api import CMakeApiType -CACHE_API = { +CACHE_API: dict[int, CMakeApiType] = { 2: CacheV2, } diff --git a/cmake_file_api/kinds/cache/v2.py b/cmake_file_api/kinds/cache/v2.py index 82e0f61..8cc3040 100644 --- a/cmake_file_api/kinds/cache/v2.py +++ b/cmake_file_api/kinds/cache/v2.py @@ -1,7 +1,7 @@ from enum import Enum import json from pathlib import Path -from typing import Dict, List +from typing import Any from cmake_file_api.kinds.common import VersionMajorMinor from cmake_file_api.kinds.kind import ObjectKind @@ -17,7 +17,7 @@ class CacheEntryType(Enum): TYPE_UNINITIALIZED = "UNINITIALIZED" -class CacheEntryProperty(object): +class CacheEntryProperty: __slots__ = ("name", "value") def __init__(self, name: str, value: str): @@ -25,7 +25,7 @@ def __init__(self, name: str, value: str): self.value = value @classmethod - def from_dict(cls, dikt: Dict) -> "CacheEntryProperty": + def from_dict(cls, dikt: dict[str, Any]) -> "CacheEntryProperty": name = dikt["name"] value = dikt["value"] return cls(name, value) @@ -38,17 +38,17 @@ def __repr__(self) -> str: ) -class CacheEntry(object): +class CacheEntry: __slots__ = ("name", "value", "type", "properties") - def __init__(self, name: str, value: str, type: CacheEntryType, properties: List[CacheEntryProperty]): + def __init__(self, name: str, value: str, type: CacheEntryType, properties: list[CacheEntryProperty]): self.name = name self.value = value self.type = type self.properties = properties @classmethod - def from_dict(cls, dikt: Dict) -> "CacheEntry": + def from_dict(cls, dikt: dict[str, Any]) -> "CacheEntry": name = dikt["name"] value = dikt["value"] type = CacheEntryType(dikt["type"]) @@ -65,17 +65,17 @@ def __repr__(self) -> str: ) -class CacheV2(object): +class CacheV2: KIND = ObjectKind.CACHE __slots__ = ("version", "entries") - def __init__(self, version: VersionMajorMinor, entries: List[CacheEntry]): + def __init__(self, version: VersionMajorMinor, entries: list[CacheEntry]): self.version = version self.entries = entries @classmethod - def from_dict(cls, dikt: Dict, reply_path) -> "CacheModelV2": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "CacheV2": if dikt["kind"] != cls.KIND.value: raise ValueError version = VersionMajorMinor.from_dict(dikt["version"]) @@ -83,7 +83,7 @@ def from_dict(cls, dikt: Dict, reply_path) -> "CacheModelV2": return cls(version, entries) @classmethod - def from_path(cls, path: Path, reply_path: Path) -> "CacheModelV2": + def from_path(cls, path: Path, reply_path: Path) -> "CacheV2": dikt = json.load(path.open()) return cls.from_dict(dikt, reply_path) diff --git a/cmake_file_api/kinds/cmakeFiles/api.py b/cmake_file_api/kinds/cmakeFiles/api.py index 89f6cc8..2d2d58e 100644 --- a/cmake_file_api/kinds/cmakeFiles/api.py +++ b/cmake_file_api/kinds/cmakeFiles/api.py @@ -1,6 +1,11 @@ +from __future__ import annotations +import typing + from .v1 import CMakeFilesV1 +if typing.TYPE_CHECKING: + from ..api import CMakeApiType -CMAKEFILES_API = { +CMAKEFILES_API: dict[int, CMakeApiType] = { 1: CMakeFilesV1, } diff --git a/cmake_file_api/kinds/cmakeFiles/v1.py b/cmake_file_api/kinds/cmakeFiles/v1.py index 164de4c..8879b7b 100644 --- a/cmake_file_api/kinds/cmakeFiles/v1.py +++ b/cmake_file_api/kinds/cmakeFiles/v1.py @@ -1,12 +1,12 @@ import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Optional from cmake_file_api.kinds.common import CMakeSourceBuildPaths, VersionMajorMinor from cmake_file_api.kinds.kind import ObjectKind -class CMakeFilesInput(object): +class CMakeFilesInput: __slots__ = ("path", "isGenerator", "isExternal", "isCMake") def __init__(self, path: Path, isGenerator: Optional[bool], isExternal: Optional[bool], isCMake: Optional[bool]): @@ -16,7 +16,7 @@ def __init__(self, path: Path, isGenerator: Optional[bool], isExternal: Optional self.isCMake = isCMake @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeFileInput": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeFilesInput": path = Path(dikt["path"]) isGenerator = dikt.get("isGenerator") isExternal = dikt.get("isExternal") @@ -33,25 +33,25 @@ def __repr__(self) -> str: ) -class CMakeFilesV1(object): +class CMakeFilesV1: KIND = ObjectKind.CMAKEFILES __slots__ = ("version", "paths", "inputs") - def __init__(self, version: VersionMajorMinor, paths: CMakeSourceBuildPaths, inputs: List[CMakeFilesInput]): + def __init__(self, version: VersionMajorMinor, paths: CMakeSourceBuildPaths, inputs: list[CMakeFilesInput]): self.version = version self.paths = paths self.inputs = inputs @classmethod - def from_dict(cls, dikt: Dict, reply_path: Path) -> "CmakeFilesV2": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "CMakeFilesV1": version = VersionMajorMinor.from_dict(dikt["version"]) paths = CMakeSourceBuildPaths.from_dict(dikt["paths"]) inputs = list(CMakeFilesInput.from_dict(cmi) for cmi in dikt["inputs"]) return cls(version, paths, inputs) @classmethod - def from_path(cls, path: Path, reply_path: Path) -> "CmakeFilesV2": + def from_path(cls, path: Path, reply_path: Path) -> "CMakeFilesV1": dikt = json.load(path.open()) return cls.from_dict(dikt, reply_path) diff --git a/cmake_file_api/kinds/codemodel/api.py b/cmake_file_api/kinds/codemodel/api.py index 2d53f32..c76998c 100644 --- a/cmake_file_api/kinds/codemodel/api.py +++ b/cmake_file_api/kinds/codemodel/api.py @@ -1,6 +1,12 @@ +from __future__ import annotations +import typing + from .v2 import CodemodelV2 -CODEMODEL_API = { +if typing.TYPE_CHECKING: + from ..api import CMakeApiType + +CODEMODEL_API: dict[int, CMakeApiType] = { 2: CodemodelV2, } diff --git a/cmake_file_api/kinds/codemodel/target/v2.py b/cmake_file_api/kinds/codemodel/target/v2.py index 0ec3928..c81e1d8 100644 --- a/cmake_file_api/kinds/codemodel/target/v2.py +++ b/cmake_file_api/kinds/codemodel/target/v2.py @@ -1,7 +1,7 @@ import enum import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Optional from cmake_file_api.kinds.common import CMakeSourceBuildPaths @@ -27,7 +27,7 @@ class ArchiveFragmentRole(enum.Enum): ARCHIVER_FLAGS = "flags" -class BacktraceNode(object): +class BacktraceNode: __slots__ = ("file", "line", "command", "parent") def __init__(self, file: Path, line: Optional[int], command: Optional[str]): @@ -37,7 +37,7 @@ def __init__(self, file: Path, line: Optional[int], command: Optional[str]): self.parent = None @classmethod - def from_dict(cls, dikt: Dict, commands: List[str], files: List[Path]) -> "BacktraceNode": + def from_dict(cls, dikt: dict[str, Any], commands: list[str], files: list[Path]) -> "BacktraceNode": file = files[dikt["file"]] line = dikt.get("line") command = None @@ -45,7 +45,7 @@ def from_dict(cls, dikt: Dict, commands: List[str], files: List[Path]) -> "Backt command = commands[dikt["command"]] return cls(file, line, command) - def update_from_dict(self, dikt: Dict, nodes: List["BacktraceNode"]) -> None: + def update_from_dict(self, dikt: dict[str, Any], nodes: list["BacktraceNode"]) -> None: if "parent" in dikt: self.parent = nodes[dikt["parent"]] @@ -58,14 +58,14 @@ def __repr__(self) -> str: ) -class BacktraceGraph(object): +class BacktraceGraph: __slots__ = ("nodes", ) - def __init__(self, nodes: List[BacktraceNode]): + def __init__(self, nodes: list[BacktraceNode]): self.nodes = nodes @classmethod - def from_dict(cls, dikt: Dict) -> "BacktraceGraph": + def from_dict(cls, dikt: dict[str, Any]) -> "BacktraceGraph": commands = dikt["commands"] files = list(Path(f) for f in dikt["files"]) nodes = list(BacktraceNode.from_dict(btn, commands, files) for btn in dikt["nodes"]) @@ -80,7 +80,7 @@ def __repr__(self) -> str: ) -class TargetDestination(object): +class TargetDestination: __slots__ = ("path", "backtrace") def __init__(self, path: Path, backtrace: BacktraceNode): @@ -88,7 +88,7 @@ def __init__(self, path: Path, backtrace: BacktraceNode): self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetDestination": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetDestination": path = Path(dikt["path"]) backtrace = backtraceGraph.nodes[dikt["backtrace"]] return cls(path, backtrace) @@ -101,15 +101,15 @@ def __repr__(self) -> str: ) -class TargetInstall(object): +class TargetInstall: __slots__ = ("prefix", "destinations") - def __init__(self, prefix: Path, destinations: List[TargetDestination]): + def __init__(self, prefix: Path, destinations: list[TargetDestination]): self.prefix = prefix self.destinations = destinations @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetInstall": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetInstall": prefix = Path(dikt["prefix"]["path"]) destinations = list(TargetDestination.from_dict(td, backtraceGraph) for td in dikt["destinations"]) return cls(prefix, destinations) @@ -122,7 +122,7 @@ def __repr__(self) -> str: ) -class TargetLinkFragment(object): +class TargetLinkFragment: __slots__ = ("fragment", "role") def __init__(self, fragment: str, role: LinkFragmentRole): @@ -130,7 +130,7 @@ def __init__(self, fragment: str, role: LinkFragmentRole): self.role = role @classmethod - def from_dict(cls, dikt: Dict) -> "TargetLinkFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetLinkFragment": fragment = dikt["fragment"] role = LinkFragmentRole(dikt["role"]) return cls(fragment, role) @@ -143,17 +143,17 @@ def __repr__(self) -> str: ) -class TargetLink(object): +class TargetLink: __slots__ = ("language", "commandFragments", "lto", "sysroot") - def __init__(self, language: str, commandFragments: List[TargetLinkFragment], lto: Optional[bool], sysroot: Optional[Path]): + def __init__(self, language: str, commandFragments: list[TargetLinkFragment], lto: Optional[bool], sysroot: Optional[Path]): self.language = language self.commandFragments = commandFragments self.lto = lto self.sysroot = sysroot @classmethod - def from_dict(cls, dikt: Dict) -> "TargetLink": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetLink": language = dikt["language"] commandFragments = [] if "commandFragments" in dikt: @@ -170,11 +170,11 @@ def __repr__(self) -> str: self.language, self.commandFragments, self.lto, - "'{}'".format(self.sysroot) if self.sysroot else None, + f"'{self.sysroot}'" if self.sysroot else None, ) -class TargetArchiveFragment(object): +class TargetArchiveFragment: __slots__ = ("fragment", "role") def __init__(self, fragment: str, role: ArchiveFragmentRole): @@ -182,7 +182,7 @@ def __init__(self, fragment: str, role: ArchiveFragmentRole): self.role = role @classmethod - def from_dict(cls, dikt: Dict) -> "TargetArchiveFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetArchiveFragment": fragment = dikt["fragment"] role = ArchiveFragmentRole(dikt["role"]) return cls(fragment, role) @@ -195,18 +195,18 @@ def __repr__(self) -> str: ) -class TargetArchive(object): +class TargetArchive: __slots__ = ("commandFragments", "lto") - def __init__(self, commandFragments: List[TargetArchiveFragment], lto: Optional[bool]): + def __init__(self, commandFragments: list[TargetArchiveFragment], lto: Optional[bool]): self.commandFragments = commandFragments self.lto = lto @classmethod - def from_dict(cls, dikt: Dict) -> "TargetArchive": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetArchive": commandFragments = [] if "commandFragments" in dikt: - commandFragments = list(TargetLinkFragment.from_dict(tlf) for tlf in dikt["commandFragments"]) + commandFragments = list(TargetArchiveFragment.from_dict(tlf) for tlf in dikt["commandFragments"]) lto = dikt.get("lto") return cls(commandFragments, lto) @@ -218,15 +218,15 @@ def __repr__(self) -> str: ) -class TargetSourceGroup(object): +class TargetSourceGroup: __slots__ = ("name", "sources") - def __init__(self, name: str, sources: List["TargetSource"]): + def __init__(self, name: str, sources: list["TargetSource"]): self.name = name - self.sources = [] + self.sources: list[TargetSource] = [] @classmethod - def from_dict(cls, dikt: Dict, target_sources: List["TargetSource"]) -> "TargetSourceGroup": + def from_dict(cls, dikt: dict[str, Any], target_sources: list["TargetSource"]) -> "TargetSourceGroup": name = dikt["name"] sources = list(target_sources[tsi] for tsi in dikt["sourceIndexes"]) return cls(name, sources) @@ -237,14 +237,14 @@ def __repr__(self) -> str: ) -class TargetCompileFragment(object): +class TargetCompileFragment: __slots__ = ("fragment", ) def __init__(self, fragment: str): self.fragment = fragment @classmethod - def from_dict(cls, dikt: Dict) -> "TargetCompileFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetCompileFragment": fragment = dikt["fragment"] return cls(fragment) @@ -255,7 +255,7 @@ def __repr__(self) -> str: ) -class TargetCompileGroupInclude(object): +class TargetCompileGroupInclude: __slots__ = ("path", "isSystem", "backtrace") def __init__(self, path: Path, isSystem: Optional[bool], backtrace: Optional[BacktraceNode]): @@ -264,7 +264,7 @@ def __init__(self, path: Path, isSystem: Optional[bool], backtrace: Optional[Bac self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupInclude": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupInclude": path = Path(dikt["path"]) isSystem = dikt.get("isSystem") backtrace = None @@ -275,21 +275,21 @@ def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompile def __repr__(self) -> str: return "{}(path={}, system={}, backtrace={})".format( type(self).__name__, - "'{}'".format(self.path) if self.path else None, + f"'{self.path}'" if self.path else None, self.isSystem, self.backtrace, ) -class TargetCompileGroupPCH(object): +class TargetCompileGroupPCH: __slots__ = ("header", "backtrace") - def __init__(self, header: Path, backtrace: BacktraceNode): + def __init__(self, header: Path, backtrace: Optional[BacktraceNode]): self.header = header self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupPCH": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupPCH": header = Path(dikt["header"]) backtrace = None if "backtrace" in dikt: @@ -304,15 +304,15 @@ def __repr__(self) -> str: ) -class TargetCompileGroupDefine(object): +class TargetCompileGroupDefine: __slots__ = ("define", "backtrace") - def __init__(self, define: str, backtrace: BacktraceNode): + def __init__(self, define: str, backtrace: Optional[BacktraceNode]): self.define = define self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupDefine": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupDefine": define = dikt["define"] backtrace = None if "backtrace" in dikt: @@ -327,12 +327,12 @@ def __repr__(self) -> str: ) -class TargetCompileGroup(object): +class TargetCompileGroup: __slots__ = ("sources", "language", "compileCommandFragments", "includes", "precompileHeaders", "defines", "sysroot") - def __init__(self, sources: List["TargetSource"], language: str, - compileCommandFragments: List[TargetCompileFragment], includes: List[TargetCompileGroupInclude], - precompileHeaders: List[TargetCompileGroupPCH], defines: List[TargetCompileGroupDefine], + def __init__(self, sources: list["TargetSource"], language: str, + compileCommandFragments: list[TargetCompileFragment], includes: list[TargetCompileGroupInclude], + precompileHeaders: list[TargetCompileGroupPCH], defines: list[TargetCompileGroupDefine], sysroot: Optional[Path]): self.sources = sources self.language = language @@ -343,7 +343,7 @@ def __init__(self, sources: List["TargetSource"], language: str, self.sysroot = sysroot @classmethod - def from_dict(cls, dikt: Dict, target_sources: List["TargetSource"], backtraceGraph: BacktraceGraph) -> "TargetCompileGroup": + def from_dict(cls, dikt: dict[str, Any], target_sources: list["TargetSource"], backtraceGraph: BacktraceGraph) -> "TargetCompileGroup": language = dikt["language"] compileCommandFragments = list(TargetCompileFragment.from_dict(tcf) for tcf in dikt.get("compileCommandFragments", ())) includes = list(TargetCompileGroupInclude.from_dict(tci, backtraceGraph) for tci in dikt.get("includes", ())) @@ -362,23 +362,23 @@ def __repr__(self) -> str: len(self.includes), len(self.precompileHeaders), len(self.defines), - "'{}'".format(self.sysroot) if self.sysroot else None, + f"'{self.sysroot}'" if self.sysroot else None, ) -class TargetDependency(object): +class TargetDependency: __slots__ = ("id", "target", "backtrace") def __init__(self, id: str, backtrace: Optional[BacktraceNode]): self.id = id - self.target = None # type: CodemodelTargetV2 + self.target: Optional[CodemodelTargetV2] = None self.backtrace = backtrace - def update_dependency(self, lut_id_target: Dict[str, "CodemodelTargetV2"]): + def update_dependency(self, lut_id_target: dict[str, "CodemodelTargetV2"]) -> None: self.target = lut_id_target[self.id] @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetDependency": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetDependency": id = dikt["id"] backtrace = None if "backtrace" in dikt: @@ -389,23 +389,23 @@ def __repr__(self) -> str: return "{}(id='{}', target='{}', backtrace={})".format( type(self).__name__, self.id, - self.target.name, + self.target.name if self.target else None, self.backtrace, ) -class TargetSource(object): +class TargetSource: __slots__ = ("path", "isGenerated", "backtrace", "compileGroup", "sourceGroup") def __init__(self, path: Path, isGenerated: Optional[bool], backtrace: Optional[BacktraceNode]): self.path = path self.isGenerated = isGenerated self.backtrace = backtrace - self.compileGroup = None # type: Optional[TargetCompileGroup] - self.sourceGroup = None # type: Optional[TargetSourceGroup] + self.compileGroup: Optional[TargetCompileGroup] = None + self.sourceGroup: Optional[TargetSourceGroup] = None @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetSource": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetSource": path = Path(dikt["path"]) isGenerated = dikt.get("isGenerated") backtrace = None @@ -413,7 +413,7 @@ def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetSource" backtrace = backtraceGraph.nodes[dikt["backtrace"]] return cls(path, isGenerated, backtrace) - def update_from_dict(self, dikt: Dict, modelTarget: "CodemodelTargetV2"): + def update_from_dict(self, dikt: dict[str, Any], modelTarget: "CodemodelTargetV2") -> None: if "compileGroupIndex" in dikt: self.compileGroup = modelTarget.compileGroups[dikt["compileGroupIndex"]] if "sourceGroupIndex" in dikt: @@ -430,17 +430,17 @@ def __repr__(self) -> str: ) -class CodemodelTargetV2(object): +class CodemodelTargetV2: __slots__ = ("name", "id", "type", "backtrace", "folder", "paths", "nameOnDisk", "artifacts", "isGeneratorProvided", "install", "link", "archive", "dependencies", "sources", "sourceGroups", "compileGroups") - def __init__(self, name: str, id: str, type: TargetType, backtrace: BacktraceNode, folder: Path, - paths: CMakeSourceBuildPaths, nameOnDisk: str, artifacts: List[Path], + def __init__(self, name: str, id: str, type: TargetType, backtrace: Optional[BacktraceNode], folder: Optional[Path], + paths: CMakeSourceBuildPaths, nameOnDisk: str, artifacts: list[Path], isGeneratorProvided: Optional[bool], install: Optional[TargetInstall], link: Optional[TargetLink], archive: Optional[TargetArchive], - dependencies: List[TargetDependency], sources: List[TargetSource], - sourceGroups: List[TargetSourceGroup], compileGroups: List[TargetCompileGroup]): + dependencies: list[TargetDependency], sources: list[TargetSource], + sourceGroups: list[TargetSourceGroup], compileGroups: list[TargetCompileGroup]): self.name = name self.id = id self.type = type @@ -458,12 +458,12 @@ def __init__(self, name: str, id: str, type: TargetType, backtrace: BacktraceNod self.sourceGroups = sourceGroups self.compileGroups = compileGroups - def update_dependencies(self, lut_id_target: Dict[str, "CodemodelTargetV2"]): + def update_dependencies(self, lut_id_target: dict[str, "CodemodelTargetV2"]) -> None: for dependency in self.dependencies: dependency.update_dependency(lut_id_target) @classmethod - def from_dict(cls, dikt: Dict, reply_path: Path) -> "CodemodelTargetV2": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "CodemodelTargetV2": name = dikt["name"] id = dikt["id"] type = TargetType(dikt["type"]) @@ -475,7 +475,7 @@ def from_dict(cls, dikt: Dict, reply_path: Path) -> "CodemodelTargetV2": if "folder" in dikt: folder = Path(dikt["folder"]["name"]) paths = CMakeSourceBuildPaths.from_dict(dikt["paths"]) - nameOnDisk = dikt.get("nameOnDisk", None) + nameOnDisk = dikt.get("nameOnDisk", "") artifacts = list(Path(p["path"]) for p in dikt.get("artifacts", ())) isGeneratorProvided = dikt.get("isGeneratorProvided") install = None diff --git a/cmake_file_api/kinds/codemodel/v2.py b/cmake_file_api/kinds/codemodel/v2.py index 51aa422..d597f0a 100644 --- a/cmake_file_api/kinds/codemodel/v2.py +++ b/cmake_file_api/kinds/codemodel/v2.py @@ -1,28 +1,28 @@ import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Optional from cmake_file_api.kinds.common import CMakeSourceBuildPaths, VersionMajorMinor from cmake_file_api.kinds.kind import ObjectKind from .target.v2 import CodemodelTargetV2 -class CMakeProject(object): +class CMakeProject: __slots__ = ("name", "parentProject", "childProjects", "directories", "targets") def __init__(self, name: str): self.name = name - self.parentProject = None # type: Optional[CMakeProject] - self.childProjects = [] # type: List[CMakeProject] - self.directories = [] # type: List[CMakeDirectory] - self.targets = [] # type:List[CMakeTarget] + self.parentProject: Optional[CMakeProject] = None + self.childProjects: list[CMakeProject] = [] + self.directories: list[CMakeDirectory] = [] + self.targets: list[CMakeTarget] = [] @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeProject": + def from_dict(cls, dikt: dict[str, str]) -> "CMakeProject": name = dikt["name"] return cls(name) - def update_from_dict(self, dikt: Dict, configuration: "CMakeConfiguration") -> None: + def update_from_dict(self, dikt: dict[str, Any], configuration: "CMakeConfiguration") -> None: if "parentIndex" in dikt: self.parentProject = configuration.projects[dikt["parentIndex"]] self.childProjects = list(configuration.projects[ti] for ti in dikt.get("childIndexes", ())) @@ -40,28 +40,28 @@ def __repr__(self) -> str: ) -class CMakeDirectory(object): +class CMakeDirectory: __slots__ = ("source", "build", "parentDirectory", "childDirectories", "project", "targets", "minimumCMakeVersion", "hasInstallRule") def __init__(self, source: Path, build: Path, minimumCMakeVersion: Optional[str], hasInstallRule: bool): self.source = source self.build = build - self.parentDirectory = None # type: Optional[CMakeDirectory] - self.childDirectories = [] # type: List[CMakeDirectory] - self.project = None # type: Optional[CMakeProject] - self.targets = [] # type: List[CMakeTarget] + self.parentDirectory: Optional[CMakeDirectory] = None + self.childDirectories: list[CMakeDirectory] = [] + self.project: Optional[CMakeProject] = None + self.targets: list[CMakeTarget] = [] self.minimumCMakeVersion = minimumCMakeVersion self.hasInstallRule = hasInstallRule @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeDirectory": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeDirectory": source = Path(dikt["source"]) build = Path(dikt["build"]) minimumCMakeVersion = dikt.get("minimumCMakeVersion", None) hasInstallRule = dikt.get("hasInstallRule", False) return cls(source, build, minimumCMakeVersion, hasInstallRule) - def update_from_dict(self, dikt: Dict, configuration: "CMakeConfiguration") -> None: + def update_from_dict(self, dikt: dict[str, Any], configuration: "CMakeConfiguration") -> None: if "parentIndex" in dikt: self.parentDirectory = configuration.directories[dikt["parentIndex"]] self.childDirectories = list(configuration.directories[di] for di in dikt.get("childIndexes", ())) @@ -73,16 +73,16 @@ def __repr__(self) -> str: type(self).__name__, self.source, self.build, - '{}'.format(self.parentDirectory) if self.parentDirectory else None, + f'{self.parentDirectory}' if self.parentDirectory else None, len(self.childDirectories), - self.project.name, + self.project.name if self.project else "", len(self.targets), self.minimumCMakeVersion, self.hasInstallRule, ) -class CMakeTarget(object): +class CMakeTarget: __slots__ = ("name", "directory", "project", "jsonFile", "target") def __init__(self, name: str, directory: CMakeDirectory, project: CMakeProject, jsonFile: Path, target: CodemodelTargetV2): @@ -92,12 +92,12 @@ def __init__(self, name: str, directory: CMakeDirectory, project: CMakeProject, self.jsonFile = jsonFile self.target = target - def update_dependencies(self, lut_id_target: Dict[str, "CMakeTarget"]): + def update_dependencies(self, lut_id_target: dict[str, "CMakeTarget"]) -> None: lut = {k: v.target for k, v in lut_id_target.items()} self.target.update_dependencies(lut) @classmethod - def from_dict(cls, dikt: Dict, directories: List[CMakeDirectory], projects: List[CMakeProject], reply_path: Path) -> "CMakeTarget": + def from_dict(cls, dikt: dict[str, Any], directories: list[CMakeDirectory], projects: list[CMakeProject], reply_path: Path) -> "CMakeTarget": name = dikt["name"] directory = directories[dikt["directoryIndex"]] project = projects[dikt["projectIndex"]] @@ -116,17 +116,17 @@ def __repr__(self) -> str: ) -class CMakeConfiguration(object): +class CMakeConfiguration: __slots__ = ("name", "directories", "projects", "targets") - def __init__(self, name: str, directories: List[CMakeDirectory], projects: List[CMakeProject], targets: List[CMakeTarget]): + def __init__(self, name: str, directories: list[CMakeDirectory], projects: list[CMakeProject], targets: list[CMakeTarget]): self.name = name self.directories = directories self.projects = projects self.targets = targets @classmethod - def from_dict(cls, dikt: Dict, reply_path: Path) -> "CMakeConfiguration": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "CMakeConfiguration": name = dikt["name"] directories = list(CMakeDirectory.from_dict(d) for d in dikt["directories"]) projects = list(CMakeProject.from_dict(d) for d in dikt["projects"]) @@ -153,18 +153,18 @@ def __repr__(self) -> str: ) -class CodemodelV2(object): +class CodemodelV2: KIND = ObjectKind.CODEMODEL __slots__ = ("version", "paths", "configurations") - def __init__(self, version: VersionMajorMinor, paths: CMakeSourceBuildPaths, configurations: List[CMakeConfiguration]): + def __init__(self, version: VersionMajorMinor, paths: CMakeSourceBuildPaths, configurations: list[CMakeConfiguration]): self.version = version self.paths = paths self.configurations = configurations @classmethod - def from_dict(cls, dikt: dict, reply_path: Path) -> "CodemodelV2": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "CodemodelV2": if dikt["kind"] != cls.KIND.value: raise ValueError paths = CMakeSourceBuildPaths.from_dict(dikt["paths"]) diff --git a/cmake_file_api/kinds/common.py b/cmake_file_api/kinds/common.py index 070d124..92efb6f 100644 --- a/cmake_file_api/kinds/common.py +++ b/cmake_file_api/kinds/common.py @@ -1,7 +1,8 @@ from pathlib import Path +from typing import Any -class VersionMajorMinor(object): +class VersionMajorMinor: __slots__ = ("major", "minor") def __init__(self, major: int, minor: int): @@ -9,7 +10,7 @@ def __init__(self, major: int, minor: int): self.minor = minor @classmethod - def from_dict(cls, d) -> "VersionMajorMinor": + def from_dict(cls, d: dict[str, str]) -> "VersionMajorMinor": return cls(int(d["major"]), int(d["minor"])) def __repr__(self) -> str: @@ -19,7 +20,7 @@ def __repr__(self) -> str: ) -class CMakeSourceBuildPaths(object): +class CMakeSourceBuildPaths: __slots__ = ("source", "build") def __init__(self, source: Path, build: Path): @@ -27,7 +28,7 @@ def __init__(self, source: Path, build: Path): self.build = build @classmethod - def from_dict(cls, d) -> "CMakeSourceBuildPaths": + def from_dict(cls, d: dict[str, Any]) -> "CMakeSourceBuildPaths": return cls(Path(d["source"]), Path(d["build"])) def __repr__(self) -> str: diff --git a/cmake_file_api/kinds/configureLog/api.py b/cmake_file_api/kinds/configureLog/api.py index d54e28c..f0b9e45 100644 --- a/cmake_file_api/kinds/configureLog/api.py +++ b/cmake_file_api/kinds/configureLog/api.py @@ -1,6 +1,11 @@ +from __future__ import annotations +import typing + from .v1 import ConfigureLogV1 +if typing.TYPE_CHECKING: + from ..api import CMakeApiType -CONFIGURELOG_API = { +CONFIGURELOG_API: dict[int, CMakeApiType] = { 1: ConfigureLogV1, } diff --git a/cmake_file_api/kinds/configureLog/target/v2.py b/cmake_file_api/kinds/configureLog/target/v2.py index a9a8575..cc7139f 100644 --- a/cmake_file_api/kinds/configureLog/target/v2.py +++ b/cmake_file_api/kinds/configureLog/target/v2.py @@ -1,7 +1,7 @@ import enum import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Optional from cmake_file_api.kinds.common import CMakeSourceBuildPaths @@ -26,7 +26,7 @@ class ArchiveFragmentRole(enum.Enum): ARCHIVER_FLAGS = "flags" -class BacktraceNode(object): +class BacktraceNode: __slots__ = ("file", "line", "command", "parent") def __init__(self, file: Path, line: Optional[int], command: Optional[str]): @@ -36,7 +36,7 @@ def __init__(self, file: Path, line: Optional[int], command: Optional[str]): self.parent = None @classmethod - def from_dict(cls, dikt: Dict, commands: List[str], files: List[Path]) -> "BacktraceNode": + def from_dict(cls, dikt: dict[str, Any], commands: list[str], files: list[Path]) -> "BacktraceNode": file = files[dikt["file"]] line = dikt.get("line") command = None @@ -44,7 +44,7 @@ def from_dict(cls, dikt: Dict, commands: List[str], files: List[Path]) -> "Backt command = commands[dikt["command"]] return cls(file, line, command) - def update_from_dict(self, dikt: Dict, nodes: List["BacktraceNode"]) -> None: + def update_from_dict(self, dikt: dict[str, Any], nodes: list["BacktraceNode"]) -> None: if "parent" in dikt: self.parent = nodes[dikt["parent"]] @@ -57,14 +57,14 @@ def __repr__(self) -> str: ) -class BacktraceGraph(object): +class BacktraceGraph: __slots__ = ("nodes", ) - def __init__(self, nodes: List[BacktraceNode]): - self.nodes = nodes + def __init__(self, nodes: list[BacktraceNode]): + self.nodes: list[BacktraceNode] = nodes @classmethod - def from_dict(cls, dikt: Dict) -> "BacktraceGraph": + def from_dict(cls, dikt: dict[str, Any]) -> "BacktraceGraph": commands = dikt["commands"] files = list(Path(f) for f in dikt["files"]) nodes = list(BacktraceNode.from_dict(btn, commands, files) for btn in dikt["nodes"]) @@ -79,7 +79,7 @@ def __repr__(self) -> str: ) -class TargetDestination(object): +class TargetDestination: __slots__ = ("path", "backtrace") def __init__(self, path: Path, backtrace: BacktraceNode): @@ -87,7 +87,7 @@ def __init__(self, path: Path, backtrace: BacktraceNode): self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetDestination": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetDestination": path = Path(dikt["path"]) backtrace = backtraceGraph.nodes[dikt["backtrace"]] return cls(path, backtrace) @@ -100,15 +100,15 @@ def __repr__(self) -> str: ) -class TargetInstall(object): +class TargetInstall: __slots__ = ("prefix", "destinations") - def __init__(self, prefix: Path, destinations: List[TargetDestination]): + def __init__(self, prefix: Path, destinations: list[TargetDestination]): self.prefix = prefix self.destinations = destinations @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetInstall": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetInstall": prefix = Path(dikt["prefix"]["path"]) destinations = list(TargetDestination.from_dict(td, backtraceGraph) for td in dikt["destinations"]) return cls(prefix, destinations) @@ -121,7 +121,7 @@ def __repr__(self) -> str: ) -class TargetLinkFragment(object): +class TargetLinkFragment: __slots__ = ("fragment", "role") def __init__(self, fragment: str, role: LinkFragmentRole): @@ -129,7 +129,7 @@ def __init__(self, fragment: str, role: LinkFragmentRole): self.role = role @classmethod - def from_dict(cls, dikt: Dict) -> "TargetLinkFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetLinkFragment": fragment = dikt["fragment"] role = LinkFragmentRole(dikt["role"]) return cls(fragment, role) @@ -142,17 +142,17 @@ def __repr__(self) -> str: ) -class TargetLink(object): +class TargetLink: __slots__ = ("language", "commandFragments", "lto", "sysroot") - def __init__(self, language: str, commandFragments: List[TargetLinkFragment], lto: Optional[bool], sysroot: Optional[Path]): + def __init__(self, language: str, commandFragments: list[TargetLinkFragment], lto: Optional[bool], sysroot: Optional[Path]): self.language = language self.commandFragments = commandFragments self.lto = lto self.sysroot = sysroot @classmethod - def from_dict(cls, dikt: Dict) -> "TargetLink": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetLink": language = dikt["language"] commandFragments = [] if "commandFragments" in dikt: @@ -169,11 +169,11 @@ def __repr__(self) -> str: self.language, self.commandFragments, self.lto, - "'{}'".format(self.sysroot) if self.sysroot else None, + f"'{self.sysroot}'" if self.sysroot else None, ) -class TargetArchiveFragment(object): +class TargetArchiveFragment: __slots__ = ("fragment", "role") def __init__(self, fragment: str, role: ArchiveFragmentRole): @@ -181,7 +181,7 @@ def __init__(self, fragment: str, role: ArchiveFragmentRole): self.role = role @classmethod - def from_dict(cls, dikt: Dict) -> "TargetArchiveFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetArchiveFragment": fragment = dikt["fragment"] role = ArchiveFragmentRole(dikt["role"]) return cls(fragment, role) @@ -194,18 +194,18 @@ def __repr__(self) -> str: ) -class TargetArchive(object): +class TargetArchive: __slots__ = ("commandFragments", "lto") - def __init__(self, commandFragments: List[TargetArchiveFragment], lto: Optional[bool]): + def __init__(self, commandFragments: list[TargetArchiveFragment], lto: Optional[bool]): self.commandFragments = commandFragments self.lto = lto @classmethod - def from_dict(cls, dikt: Dict) -> "TargetArchive": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetArchive": commandFragments = [] if "commandFragments" in dikt: - commandFragments = list(TargetLinkFragment.from_dict(tlf) for tlf in dikt["commandFragments"]) + commandFragments = list(TargetArchiveFragment.from_dict(tlf) for tlf in dikt["commandFragments"]) lto = dikt.get("lto") return cls(commandFragments, lto) @@ -217,15 +217,15 @@ def __repr__(self) -> str: ) -class TargetSourceGroup(object): +class TargetSourceGroup: __slots__ = ("name", "sources") - def __init__(self, name: str, sources: List["TargetSource"]): + def __init__(self, name: str, sources: list["TargetSource"]): self.name = name - self.sources = [] + self.sources: list[TargetSource] = [] @classmethod - def from_dict(cls, dikt: Dict, target_sources: List["TargetSource"]) -> "TargetSourceGroup": + def from_dict(cls, dikt: dict[str, Any], target_sources: list["TargetSource"]) -> "TargetSourceGroup": name = dikt["name"] sources = list(target_sources[tsi] for tsi in dikt["sourceIndexes"]) return cls(name, sources) @@ -236,14 +236,14 @@ def __repr__(self) -> str: ) -class TargetCompileFragment(object): +class TargetCompileFragment: __slots__ = ("fragment", ) def __init__(self, fragment: str): self.fragment = fragment @classmethod - def from_dict(cls, dikt: Dict) -> "TargetCompileFragment": + def from_dict(cls, dikt: dict[str, Any]) -> "TargetCompileFragment": fragment = dikt["fragment"] return cls(fragment) @@ -254,7 +254,7 @@ def __repr__(self) -> str: ) -class TargetCompileGroupInclude(object): +class TargetCompileGroupInclude: __slots__ = ("path", "isSystem", "backtrace") def __init__(self, path: Path, isSystem: Optional[bool], backtrace: Optional[BacktraceNode]): @@ -263,7 +263,7 @@ def __init__(self, path: Path, isSystem: Optional[bool], backtrace: Optional[Bac self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupInclude": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupInclude": path = Path(dikt["path"]) isSystem = dikt.get("isSystem") backtrace = None @@ -274,21 +274,21 @@ def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompile def __repr__(self) -> str: return "{}(path={}, system={}, backtrace={})".format( type(self).__name__, - "'{}'".format(self.path) if self.path else None, + f"'{self.path}'" if self.path else None, self.isSystem, self.backtrace, ) -class TargetCompileGroupPCH(object): +class TargetCompileGroupPCH: __slots__ = ("header", "backtrace") - def __init__(self, header: Path, backtrace: BacktraceNode): + def __init__(self, header: Path, backtrace: Optional[BacktraceNode]): self.header = header self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupPCH": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupPCH": header = Path(dikt["header"]) backtrace = None if "backtrace" in dikt: @@ -303,15 +303,15 @@ def __repr__(self) -> str: ) -class TargetCompileGroupDefine(object): +class TargetCompileGroupDefine: __slots__ = ("define", "backtrace") - def __init__(self, define: str, backtrace: BacktraceNode): + def __init__(self, define: str, backtrace: Optional[BacktraceNode]): self.define = define self.backtrace = backtrace @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetCompileGroupDefine": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetCompileGroupDefine": define = dikt["define"] backtrace = None if "backtrace" in dikt: @@ -326,12 +326,12 @@ def __repr__(self) -> str: ) -class TargetCompileGroup(object): +class TargetCompileGroup: __slots__ = ("sources", "language", "compileCommandFragments", "includes", "precompileHeaders", "defines", "sysroot") - def __init__(self, sources: List["TargetSource"], language: str, - compileCommandFragments: List[TargetCompileFragment], includes: List[TargetCompileGroupInclude], - precompileHeaders: List[TargetCompileGroupPCH], defines: List[TargetCompileGroupDefine], + def __init__(self, sources: list["TargetSource"], language: str, + compileCommandFragments: list[TargetCompileFragment], includes: list[TargetCompileGroupInclude], + precompileHeaders: list[TargetCompileGroupPCH], defines: list[TargetCompileGroupDefine], sysroot: Optional[Path]): self.sources = sources self.language = language @@ -342,7 +342,7 @@ def __init__(self, sources: List["TargetSource"], language: str, self.sysroot = sysroot @classmethod - def from_dict(cls, dikt: Dict, target_sources: List["TargetSource"], backtraceGraph: BacktraceGraph) -> "TargetCompileGroup": + def from_dict(cls, dikt: dict[str, Any], target_sources: list["TargetSource"], backtraceGraph: BacktraceGraph) -> "TargetCompileGroup": language = dikt["language"] compileCommandFragments = list(TargetCompileFragment.from_dict(tcf) for tcf in dikt.get("compileCommandFragments", ())) includes = list(TargetCompileGroupInclude.from_dict(tci, backtraceGraph) for tci in dikt.get("includes", ())) @@ -361,23 +361,23 @@ def __repr__(self) -> str: len(self.includes), len(self.precompileHeaders), len(self.defines), - "'{}'".format(self.sysroot) if self.sysroot else None, + f"'{self.sysroot}'" if self.sysroot else None, ) -class TargetDependency(object): +class TargetDependency: __slots__ = ("id", "target", "backtrace") def __init__(self, id: str, backtrace: Optional[BacktraceNode]): self.id = id - self.target = None # type: CodemodelTargetV2 + self.target: Optional[CodemodelTargetV2] = None self.backtrace = backtrace - def update_dependency(self, lut_id_target: Dict[str, "CodemodelTargetV2"]): + def update_dependency(self, lut_id_target: dict[str, "CodemodelTargetV2"]) -> None: self.target = lut_id_target[self.id] @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetDependency": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetDependency": id = dikt["id"] backtrace = None if "backtrace" in dikt: @@ -388,23 +388,23 @@ def __repr__(self) -> str: return "{}(id='{}', target='{}', backtrace={})".format( type(self).__name__, self.id, - self.target.name, + self.target.name if self.target else None, self.backtrace, ) -class TargetSource(object): +class TargetSource: __slots__ = ("path", "isGenerated", "backtrace", "compileGroup", "sourceGroup") def __init__(self, path: Path, isGenerated: Optional[bool], backtrace: Optional[BacktraceNode]): self.path = path self.isGenerated = isGenerated self.backtrace = backtrace - self.compileGroup = None # type: Optional[TargetCompileGroup] - self.sourceGroup = None # type: Optional[TargetSourceGroup] + self.compileGroup: Optional[TargetCompileGroup] = None + self.sourceGroup: Optional[TargetSourceGroup] = None @classmethod - def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetSource": + def from_dict(cls, dikt: dict[str, Any], backtraceGraph: BacktraceGraph) -> "TargetSource": path = Path(dikt["path"]) isGenerated = dikt.get("isGenerated") backtrace = None @@ -412,7 +412,7 @@ def from_dict(cls, dikt: Dict, backtraceGraph: BacktraceGraph) -> "TargetSource" backtrace = backtraceGraph.nodes[dikt["backtrace"]] return cls(path, isGenerated, backtrace) - def update_from_dict(self, dikt: Dict, modelTarget: "CodemodelTargetV2"): + def update_from_dict(self, dikt: dict[str, Any], modelTarget: "CodemodelTargetV2") -> None: if "compileGroupIndex" in dikt: self.compileGroup = modelTarget.compileGroups[dikt["compileGroupIndex"]] if "sourceGroupIndex" in dikt: @@ -429,17 +429,17 @@ def __repr__(self) -> str: ) -class CodemodelTargetV2(object): +class CodemodelTargetV2: __slots__ = ("name", "id", "type", "backtrace", "folder", "paths", "nameOnDisk", "artifacts", "isGeneratorProvided", "install", "link", "archive", "dependencies", "sources", "sourceGroups", "compileGroups") - def __init__(self, name: str, id: str, type: TargetType, backtrace: BacktraceNode, folder: Path, - paths: CMakeSourceBuildPaths, nameOnDisk: str, artifacts: List[Path], + def __init__(self, name: str, id: str, type: TargetType, backtrace: Optional[BacktraceNode], folder: Optional[Path], + paths: CMakeSourceBuildPaths, nameOnDisk: str, artifacts: list[Path], isGeneratorProvided: Optional[bool], install: Optional[TargetInstall], link: Optional[TargetLink], archive: Optional[TargetArchive], - dependencies: List[TargetDependency], sources: List[TargetSource], - sourceGroups: List[TargetSourceGroup], compileGroups: List[TargetCompileGroup]): + dependencies: list[TargetDependency], sources: list[TargetSource], + sourceGroups: list[TargetSourceGroup], compileGroups: list[TargetCompileGroup]): self.name = name self.id = id self.type = type @@ -457,24 +457,24 @@ def __init__(self, name: str, id: str, type: TargetType, backtrace: BacktraceNod self.sourceGroups = sourceGroups self.compileGroups = compileGroups - def update_dependencies(self, lut_id_target: Dict[str, "CodemodelTargetV2"]): + def update_dependencies(self, lut_id_target: dict[str, "CodemodelTargetV2"]) -> None: for dependency in self.dependencies: dependency.update_dependency(lut_id_target) @classmethod - def from_dict(cls, dikt: Dict, reply_path: Path) -> "CodemodelTargetV2": + def from_dict(cls, dikt: dict[str, Any]) -> "CodemodelTargetV2": name = dikt["name"] id = dikt["id"] type = TargetType(dikt["type"]) backtraceGraph = BacktraceGraph.from_dict(dikt["backtraceGraph"]) - backtrace = None + backtrace: Optional[BacktraceNode] = None if "backtrace" in dikt: backtrace = backtraceGraph.nodes[dikt["backtrace"]] folder = None if "folder" in dikt: folder = Path(dikt["folder"]["name"]) paths = CMakeSourceBuildPaths.from_dict(dikt["paths"]) - nameOnDisk = dikt.get("nameOnDisk", None) + nameOnDisk = dikt.get("nameOnDisk", "") artifacts = list(Path(p["path"]) for p in dikt.get("artifacts", ())) isGeneratorProvided = dikt.get("isGeneratorProvided") install = None @@ -497,9 +497,9 @@ def from_dict(cls, dikt: Dict, reply_path: Path) -> "CodemodelTargetV2": isGeneratorProvided, install, link, archive, dependencies, sources, sourceGroups, compileGroups) @classmethod - def from_path(cls, file: Path, reply_path: Path) -> "CodemodelTargetV2": + def from_path(cls, file: Path) -> "CodemodelTargetV2": dikt = json.load(file.open()) - return cls.from_dict(dikt, reply_path) + return cls.from_dict(dikt) def __repr__(self) -> str: return "{}(name='{}', type={}, backtrace={})".format( diff --git a/cmake_file_api/kinds/configureLog/v1.py b/cmake_file_api/kinds/configureLog/v1.py index 6cb3d75..13a1187 100644 --- a/cmake_file_api/kinds/configureLog/v1.py +++ b/cmake_file_api/kinds/configureLog/v1.py @@ -1,24 +1,23 @@ import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any -from cmake_file_api.kinds.common import CMakeSourceBuildPaths, VersionMajorMinor +from cmake_file_api.kinds.common import VersionMajorMinor from cmake_file_api.kinds.kind import ObjectKind -from .target.v2 import CodemodelTargetV2 -class ConfigureLogV1(object): +class ConfigureLogV1: KIND = ObjectKind.CONFIGURELOG __slots__ = ("version", "path", "eventKindNames") - def __init__(self, version: VersionMajorMinor, path: Path, eventKindNames: List[str]): + def __init__(self, version: VersionMajorMinor, path: Path, eventKindNames: list[str]): self.version = version self.path = path self.eventKindNames = eventKindNames @classmethod - def from_dict(cls, dikt: dict, reply_path: Path) -> "ConfigureLogV1": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "ConfigureLogV1": if dikt["kind"] != cls.KIND.value: raise ValueError path = Path(dikt["path"]) @@ -35,6 +34,6 @@ def __repr__(self) -> str: return "{}(version={}, paths={}, configurations={})".format( type(self).__name__, self.version, - self.paths, - self.configurations, + self.path, + self.eventKindNames, ) diff --git a/cmake_file_api/kinds/toolchains/api.py b/cmake_file_api/kinds/toolchains/api.py index bc4dece..d37d362 100644 --- a/cmake_file_api/kinds/toolchains/api.py +++ b/cmake_file_api/kinds/toolchains/api.py @@ -1,6 +1,11 @@ +from __future__ import annotations +import typing + from .v1 import ToolchainsV1 +if typing.TYPE_CHECKING: + from ..api import CMakeApiType -TOOLCHAINS_API = { +TOOLCHAINS_API: dict[int, CMakeApiType] = { 1: ToolchainsV1, } diff --git a/cmake_file_api/kinds/toolchains/v1.py b/cmake_file_api/kinds/toolchains/v1.py index c276cf9..2267209 100644 --- a/cmake_file_api/kinds/toolchains/v1.py +++ b/cmake_file_api/kinds/toolchains/v1.py @@ -1,22 +1,22 @@ import json from pathlib import Path -from typing import Dict, List, Optional +from typing import Any, Optional from cmake_file_api.kinds.common import VersionMajorMinor from cmake_file_api.kinds.kind import ObjectKind -class CMakeToolchainCompilerImplicit(object): +class CMakeToolchainCompilerImplicit: __slots__ = ("includeDirectories", "linkDirectories", "linkFrameworkDirectories", "linkLibraries") - def __init__(self): - self.includeDirectories = [] # type: List[Path] - self.linkDirectories = [] # type: List[Path] - self.linkFrameworkDirectories = [] # type: List[Path] - self.linkLibraries = [] # type: List[str] + def __init__(self) -> None: + self.includeDirectories: list[Path] = [] + self.linkDirectories: list[Path] = [] + self.linkFrameworkDirectories: list[Path] = [] + self.linkLibraries: list[str] = [] @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeToolchainCompilerImplicit": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeToolchainCompilerImplicit": res = cls() if "includeDirectories" in dikt: res.includeDirectories.extend(Path(p) for p in dikt["includeDirectories"]) @@ -29,7 +29,7 @@ def from_dict(cls, dikt: Dict) -> "CMakeToolchainCompilerImplicit": return res -class CMakeToolchainCompiler(object): +class CMakeToolchainCompiler: __slots__ = ("id", "path", "target", "version", "implicit") def __init__(self, id: Optional[str], path: Optional[Path], target: Optional[str], version: Optional[str], implicit: CMakeToolchainCompilerImplicit): @@ -40,7 +40,7 @@ def __init__(self, id: Optional[str], path: Optional[Path], target: Optional[str self.implicit = implicit @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeToolchainCompiler": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeToolchainCompiler": id = dikt.get("id") path = Path(dikt["path"]) if "path" in dikt else None target = dikt.get("target") @@ -58,16 +58,16 @@ def __repr__(self) -> str: ) -class CMakeToolchain(object): +class CMakeToolchain: __slots__ = ("language", "compiler", "sourceFileExtensions") - def __init__(self, language: str, compiler: CMakeToolchainCompiler, sourceFileExtensions: Optional[List[str]]): + def __init__(self, language: str, compiler: CMakeToolchainCompiler, sourceFileExtensions: Optional[list[str]]): self.language = language self.compiler = compiler self.sourceFileExtensions = sourceFileExtensions @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeToolchain": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeToolchain": language = dikt["language"] compiler = CMakeToolchainCompiler.from_dict(dikt["compiler"]) sourceFileExtensions = dikt.get("sourceFileExtensions") @@ -82,17 +82,17 @@ def __repr__(self) -> str: ) -class ToolchainsV1(object): +class ToolchainsV1: KIND = ObjectKind.TOOLCHAINS __slots__ = ("version", "toolchains") - def __init__(self, version: VersionMajorMinor, toolchains: List[CMakeToolchain]): + def __init__(self, version: VersionMajorMinor, toolchains: list[CMakeToolchain]): self.version = version self.toolchains = toolchains @classmethod - def from_dict(cls, dikt: Dict, reply_path: Path) -> "ToolchainsV1": + def from_dict(cls, dikt: dict[str, Any], reply_path: Path) -> "ToolchainsV1": version = VersionMajorMinor.from_dict(dikt["version"]) toolchains = list(CMakeToolchain.from_dict(cmi) for cmi in dikt["toolchains"]) return cls(version, toolchains) diff --git a/cmake_file_api/py.typed b/cmake_file_api/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/cmake_file_api/reply/index/file/v1.py b/cmake_file_api/reply/index/file/v1.py index 3c30d2d..22f539b 100644 --- a/cmake_file_api/reply/index/file/v1.py +++ b/cmake_file_api/reply/index/file/v1.py @@ -1,18 +1,18 @@ from pathlib import Path -from typing import Dict +from typing import Any from cmake_file_api.kinds.kind import ObjectKind from cmake_file_api.kinds.common import VersionMajorMinor -class CMakeReplyFileReferenceV1(object): +class CMakeReplyFileReferenceV1: def __init__(self, kind: ObjectKind, version: VersionMajorMinor, jsonFile: Path): self.kind = kind self.version = version self.jsonFile = jsonFile @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeReplyFileReferenceV1": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeReplyFileReferenceV1": kind = ObjectKind(dikt["kind"]) version = VersionMajorMinor.from_dict(dikt["version"]) jsonFile = Path(dikt["jsonFile"]) diff --git a/cmake_file_api/reply/index/v1.py b/cmake_file_api/reply/index/v1.py index d3cfed0..a74e64f 100644 --- a/cmake_file_api/reply/index/v1.py +++ b/cmake_file_api/reply/index/v1.py @@ -1,14 +1,13 @@ import json from pathlib import Path import re -from typing import Dict, List, Tuple - +from typing import Any from cmake_file_api.kinds.kind import ObjectKind from .file.v1 import CMakeReplyFileReferenceV1 -class CMakeGenerator(object): +class CMakeGenerator: __slots__ = ("name", "multiConfig") def __init__(self, name: str, multiConfig: bool): @@ -16,7 +15,7 @@ def __init__(self, name: str, multiConfig: bool): self.multiConfig = multiConfig @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeGenerator": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeGenerator": name = dikt["name"] multiConfig = dikt["multiConfig"] return cls(name, multiConfig) @@ -29,7 +28,7 @@ def __repr__(self) -> str: ) -class CMakeVersion(object): +class CMakeVersion: def __init__(self, major: int, minor: int, patch: int, string: str, suffix: str, isDirty: bool): self.major = major self.minor = minor @@ -39,7 +38,7 @@ def __init__(self, major: int, minor: int, patch: int, string: str, suffix: str, self.isDirty = isDirty @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeVersion": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeVersion": major = dikt["major"] minor = dikt["minor"] patch = dikt["patch"] @@ -60,7 +59,7 @@ def __repr__(self) -> str: ) -class CMakePaths(object): +class CMakePaths: __slots__ = ("cmake", "cpack", "ctest", "root") def __init__(self, cmake: Path, cpack: Path, ctest: Path, root: Path): @@ -70,7 +69,7 @@ def __init__(self, cmake: Path, cpack: Path, ctest: Path, root: Path): self.root = root @classmethod - def from_dict(cls, dikt: Dict) -> "CMakePaths": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakePaths": cmake = Path(dikt["cmake"]) cpack = Path(dikt["cpack"]) ctest = Path(dikt["ctest"]) @@ -87,7 +86,7 @@ def __str__(self) -> str: ) -class CMakeInfo(object): +class CMakeInfo: __slots__ = ("version", "paths", "generator") def __init__(self, version: CMakeVersion, paths: CMakePaths, generator: CMakeGenerator): @@ -96,7 +95,7 @@ def __init__(self, version: CMakeVersion, paths: CMakePaths, generator: CMakeGen self.generator = generator @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeInfo": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeInfo": version = CMakeVersion.from_dict(dikt["version"]) paths = CMakePaths.from_dict(dikt["paths"]) generator = CMakeGenerator.from_dict(dikt["generator"]) @@ -111,17 +110,17 @@ def __str__(self) -> str: ) -class CMakeReply(object): +class CMakeReply: __slots__ = ("stateless", "stateful", "unknowns") - def __init__(self, stateless: Dict[Tuple[ObjectKind, int], CMakeReplyFileReferenceV1], - stateful: Dict[str, Dict], unknowns: List[str]): + def __init__(self, stateless: dict[tuple[ObjectKind, int], CMakeReplyFileReferenceV1], + stateful: dict[str, dict[str, Any]], unknowns: list[str]): self.stateless = stateless self.stateful = stateful self.unknowns = unknowns @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeReply": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeReply": stateless = {} stateful = {} unknowns = [] @@ -141,16 +140,16 @@ def from_dict(cls, dikt: Dict) -> "CMakeReply": return cls(stateless, stateful, unknowns) -class CMakeReplyFileV1(object): +class CMakeReplyFileV1: __slots__ = ("cmake", "objects", "reply") - def __init__(self, cmake: CMakeInfo, objects: List[CMakeReplyFileReferenceV1], reply: CMakeReply): + def __init__(self, cmake: CMakeInfo, objects: list[CMakeReplyFileReferenceV1], reply: CMakeReply): self.cmake = cmake self.objects = objects self.reply = reply @classmethod - def from_dict(cls, dikt: Dict) -> "CMakeReplyFileV1": + def from_dict(cls, dikt: dict[str, Any]) -> "CMakeReplyFileV1": cmake = CMakeInfo.from_dict(dikt["cmake"]) objects = list(CMakeReplyFileReferenceV1.from_dict(do) for do in dikt["objects"]) reply = CMakeReply.from_dict(dikt["reply"]) diff --git a/cmake_file_api/reply/v1/api.py b/cmake_file_api/reply/v1/api.py index a48a20d..5ac3745 100644 --- a/cmake_file_api/reply/v1/api.py +++ b/cmake_file_api/reply/v1/api.py @@ -1,13 +1,14 @@ from pathlib import Path -from typing import Dict, Optional +from typing import Any, Optional from cmake_file_api.errors import CMakeException -from cmake_file_api.kinds.api import OBJECT_KINDS_API +from cmake_file_api.kinds.api import CMakeApiType, OBJECT_KINDS_API from cmake_file_api.reply.index.api import INDEX_API from cmake_file_api.kinds.kind import ObjectKind +from cmake_file_api.reply.index.v1 import CMakeReplyFileV1 -class CMakeFileApiV1(object): +class CMakeFileApiV1: __slots__ = ("_build_path", ) def __init__(self, build_path: Path): @@ -17,19 +18,19 @@ def _create_query_path(self) -> Path: result = self._build_path / ".cmake" / "api" / "v1" / "query" result.mkdir(parents=True, exist_ok=True) if not result.is_dir(): - raise NotADirectoryError("Query path '{}' is not a directory".format(result)) + raise NotADirectoryError(f"Query path '{result}' is not a directory") return result def _create_reply_path(self) -> Path: result = self._build_path / ".cmake" / "api" / "v1" / "reply" result.mkdir(parents=True, exist_ok=True) if not result.is_dir(): - raise NotADirectoryError("Reply path '{}' is not a directory".format(result)) + raise NotADirectoryError(f"Reply path '{result}' is not a directory") return result @staticmethod def _instrument_query_path(query_path: Path, kind: ObjectKind, kind_version: int) -> None: - (query_path / "{}-v{}".format(kind.value, kind_version)).touch() + (query_path / f"{kind.value}-v{kind_version}").touch() @staticmethod def _find_index_path(reply_path: Path) -> Optional[Path]: @@ -52,7 +53,7 @@ def instrument_all(self) -> None: for kind_version in kind_api.keys(): self._instrument_query_path(query_path, kind, kind_version) - def _index(self, reply_path: Path): + def _index(self, reply_path: Path) -> CMakeReplyFileV1: index_path = self._find_index_path(reply_path) if index_path is None: raise CMakeException("CMake did not generate index file. Maybe your cmake version is too old?") @@ -62,27 +63,27 @@ def _index(self, reply_path: Path): raise CMakeException("Unknown api version") return index_api.from_path(index_path) - def index(self): + def index(self) -> CMakeReplyFileV1: reply_path = self._create_reply_path() return self._index(reply_path) - def inspect(self, kind: ObjectKind, kind_version: int): + def inspect(self, kind: ObjectKind, kind_version: int) -> Optional[CMakeApiType]: reply_path = self._create_reply_path() index = self._index(reply_path) data_path = index.reply.stateless.get((kind, kind_version), None) if data_path is None: return None - api = OBJECT_KINDS_API.get(kind, {}).get(kind_version, None) + api: Optional[CMakeApiType] = OBJECT_KINDS_API.get(kind, {}).get(kind_version, None) if api is None: return None return api.from_path(reply_path / str(data_path.jsonFile), reply_path) - def inspect_all(self) -> Dict[ObjectKind, Dict[int, object]]: + def inspect_all(self) -> dict[ObjectKind, dict[int, object]]: reply_path = self._create_reply_path() index = self._index(reply_path) - result = {} + result: dict[ObjectKind, dict[int, Any]] = {} for (kind, kind_version), reply_file_ref in index.reply.stateless.items(): api = OBJECT_KINDS_API.get(kind, {}).get(kind_version, None) if api is None: diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..601a8be --- /dev/null +++ b/mypy.ini @@ -0,0 +1,3 @@ +[mypy] + +files = cmake_file_api diff --git a/requirements-dev.txt b/requirements-dev.txt index e079f8a..4bfa28c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1 +1,2 @@ pytest +mypy diff --git a/setup.cfg b/setup.cfg index 2c6cbac..019511c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,9 +16,9 @@ classifiers = Operating System :: OS Independent [options] -python_requires = >=3.6 +python_requires = >=3.9 packages=find: -setup_requires = +setup_requires = setuptools_scm [options.packages.find]