Skip to content

feat: support file API reading #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,13 @@ jobs:
runs-on: [ubuntu-latest, macos-latest, windows-latest]

include:
- python-version: pypy-3.8
- python-version: "pypy-3.8"
runs-on: ubuntu-latest
- python-version: "3.8"
runs-on: ubuntu-latest
- python-version: "3.9"
runs-on: ubuntu-latest
- python-version: "3.10"
runs-on: ubuntu-latest

steps:
Expand All @@ -55,7 +61,7 @@ jobs:
run: python -m pip install .[test]

- name: Test package
run: python -m pytest -ra
run: python -m pytest -ra --showlocals

dist:
name: Distribution build
Expand Down
5 changes: 4 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ repos:
args: ["--pytest-test-first"]
- id: requirements-txt-fixer
- id: trailing-whitespace
exclude: "^tests"

- repo: https://github.com./pre-commit/pygrep-hooks
rev: v1.9.0
Expand All @@ -37,6 +38,7 @@ repos:
- id: prettier
types_or: [yaml, markdown, html, css, scss, javascript, json]
args: [--prose-wrap=always]
exclude: "^tests"

- repo: https://github.com./asottile/blacken-docs
rev: v1.12.1
Expand All @@ -48,7 +50,6 @@ repos:
rev: 5.10.1
hooks:
- id: isort
args: ["-a", "from __future__ import annotations"] # Python 3.7+

- repo: https://github.com./asottile/pyupgrade
rev: v2.37.3
Expand Down Expand Up @@ -87,6 +88,8 @@ repos:
args: []
additional_dependencies:
- packaging
- cattrs
- rich

- repo: https://github.com./codespell-project/codespell
rev: v2.2.1
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ config.install(prefix)

Works.

If you want to access the File API, use:

```python
from scikit_build_core.fileapi.query import stateless_query
from scikit_build_core.fileapi.reply import load_reply_dir

reply_dir = stateless_query(config.build_dir)
config.configure()
index = load_reply_dir(reply_dir)
```

This mostly wraps the FileAPI in classes. It autoloads some jsonFiles. This
throws an `ExceptionGroup` if parsing files. It is currently experimental.

<!-- prettier-ignore-start -->
[actions-badge]: https://github.com./henryiii/scikit-build-core/workflows/CI/badge.svg
[actions-link]: https://github.com./henryiii/scikit-build-core/actions
Expand Down
2 changes: 1 addition & 1 deletion noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def pylint(session: nox.Session) -> None:
"""
# This needs to be installed into the package environment, and is slower
# than a pre-commit check
session.install("-e.", "pylint")
session.install("-e.[dev]", "pylint")
session.run("pylint", "src", *session.posargs)


Expand Down
18 changes: 14 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,29 @@ classifiers = [
dynamic = ["version"]

dependencies = [
"typing_extensions >=3.7; python_version<'3.8'",
"exceptiongroup; python_version<'3.11'",
"packaging", # TODO: set a min version
"typing_extensions >=3.7; python_version<'3.8'",
]

[project.optional-dependencies]
test = [
"cattrs;platform_python_implementation!='PyPy'",
"cmake",
"ninja; platform_system!='Windows'",
"pytest >=7",
"pytest-subprocess",
]
dev = [
"cattrs;platform_python_implementation!='PyPy'",
"pytest >=7",
"pytest-subprocess",
"rich",
]
docs = [
"Sphinx>=4.0",
"myst_parser>=0.13",
"furo",
"myst_parser>=0.13",
"sphinx>=4.0",
"sphinx_copybutton",
]

Expand All @@ -60,13 +65,17 @@ version.path = "src/scikit_build_core/__init__.py"

[tool.pytest.ini_options]
minversion = "7.0"
addopts = ["-ra", "--showlocals", "--strict-markers", "--strict-config"]
addopts = ["-ra", "--strict-markers", "--strict-config"]
xfail_strict = true
filterwarnings = ["error"]
log_cli_level = "info"
testpaths = [
"tests",
]
markers = [
"compile: Compiles code",
"configure: Configures CMake code",
]


[tool.mypy]
Expand Down Expand Up @@ -96,6 +105,7 @@ messages_control.disable = [
"design",
"fixme",
"import-outside-toplevel",
"invalid-name",
"line-too-long",
"missing-class-docstring",
"missing-function-docstring",
Expand Down
1 change: 0 additions & 1 deletion src/scikit_build_core/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def exception(self, msg: str, *args: Any, **kwargs: Any) -> None:
def log(self, level: int, msg: str, *args: Any, **kwargs: Any) -> None:
self.logger.log(level, FStringMessage(msg, *args, **kwargs))

# pylint: disable-next=invalid-name
def setLevel(self, level: int) -> None:
self.logger.setLevel(level)

Expand Down
1 change: 1 addition & 0 deletions src/scikit_build_core/file_api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from __future__ import annotations
69 changes: 69 additions & 0 deletions src/scikit_build_core/file_api/_cattrs_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# pylint: disable=duplicate-code

import json
from pathlib import Path
from typing import Any, Dict, Type, TypeVar

import cattr
import cattr.preconf.json

from .model.cache import Cache
from .model.cmakefiles import CMakeFiles
from .model.codemodel import CodeModel, Target
from .model.index import Index, Reply

T = TypeVar("T")

__all__ = ["make_converter", "load_reply_dir"]


def to_path(path: str, _: Type[Path]) -> Path:
return Path(path)


def make_converter(base_dir: Path) -> cattr.preconf.json.JsonConverter:
converter = cattr.preconf.json.make_converter()
converter.register_structure_hook(Path, to_path)

st_hook = cattr.gen.make_dict_structure_fn(
Reply,
converter,
codemodel_v2=cattr.gen.override(rename="codemodel-v2"),
cache_v2=cattr.gen.override(rename="cache-v2"),
cmakefiles_v1=cattr.gen.override(rename="cmakeFiles-v1"),
toolchains_v1=cattr.gen.override(rename="toolchains-v1"),
)
converter.register_structure_hook(Reply, st_hook)

def from_json_file(with_path: Dict[str, Any], t: Type[T]) -> T:
path = base_dir / Path(with_path["jsonFile"])
raw = json.loads(path.read_text(encoding="utf-8"))
return converter.structure_attrs_fromdict(raw, t)

converter.register_structure_hook(CodeModel, from_json_file)
converter.register_structure_hook(Target, from_json_file)
converter.register_structure_hook(Cache, from_json_file)
converter.register_structure_hook(CMakeFiles, from_json_file)
return converter


def load_reply_dir(reply_dir: Path) -> Index:
converter = make_converter(reply_dir)
indexes = sorted(reply_dir.glob("index-*"))
if not indexes:
raise IndexError(f"index file not found in {reply_dir}")
index_file = indexes[-1]
return converter.loads(index_file.read_text(), Index)


if __name__ == "__main__":
import argparse

import rich

parser = argparse.ArgumentParser()
parser.add_argument("reply_dir", type=Path, help="Path to the reply directory")
args = parser.parse_args()

reply = Path(args.reply_dir)
rich.print(load_reply_dir(reply))
1 change: 1 addition & 0 deletions src/scikit_build_core/file_api/model/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from __future__ import annotations
25 changes: 25 additions & 0 deletions src/scikit_build_core/file_api/model/cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import dataclasses
from typing import List

from .common import APIVersion


@dataclasses.dataclass
class Property:
name: str
value: str


@dataclasses.dataclass
class Entry:
name: str
value: str
type: str
properties: List[Property]


@dataclasses.dataclass
class Cache:
kind: str
version: APIVersion
entries: List[Entry]
20 changes: 20 additions & 0 deletions src/scikit_build_core/file_api/model/cmakefiles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import dataclasses
from pathlib import Path
from typing import List

from .common import Paths


@dataclasses.dataclass
class Input:
path: Path
isGenerated: bool = False
isExternal: bool = False
isCMake: bool = False


@dataclasses.dataclass
class CMakeFiles:
kind: str
paths: Paths
inputs: List[Input]
Loading