Skip to content

Commit 1879aa9

Browse files
authored
Merge pull request #178 from rstudio/feat-manifest-compat
Feat manifest compat
2 parents c975969 + 3ac8dfb commit 1879aa9

File tree

13 files changed

+167
-11
lines changed

13 files changed

+167
-11
lines changed

pins/boards.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ def info(self, path):
5353

5454

5555
class BaseBoard:
56+
reserved_pin_names = {"_pins.yaml"}
57+
5658
def __init__(
5759
self,
5860
board: "str | Path",
@@ -174,8 +176,11 @@ def pin_list(self):
174176
This is a low-level function; use pin_search() to get more data about
175177
each pin in a convenient form.
176178
"""
179+
177180
full_paths = self.fs.ls(self.board)
178-
return list(map(self.keep_final_path_component, full_paths))
181+
pin_names = map(self.keep_final_path_component, full_paths)
182+
183+
return [name for name in pin_names if name not in self.reserved_pin_names]
179184

180185
def pin_fetch(self, name: str, version: Optional[str] = None) -> Meta:
181186
meta = self.pin_meta(name, version)
@@ -513,6 +518,8 @@ def validate_pin_name(self, name: str) -> None:
513518

514519
if "/" in name:
515520
raise ValueError(f"Invalid pin name: {name}")
521+
elif name in self.reserved_pin_names:
522+
raise ValueError(f"The pin name '{name}' is reserved for internal use.")
516523

517524
def path_to_pin(self, name: str) -> str:
518525
self.validate_pin_name(name)

pins/meta.py

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from typing import ClassVar
2-
from dataclasses import dataclass, asdict, field
2+
from dataclasses import dataclass, asdict, field, fields, InitVar
33
from pathlib import Path
44

55
import yaml
66

7-
from typing import Mapping, Union, Sequence, Optional
7+
from typing import Mapping, Union, Sequence, Optional, List
88

99
from .versions import VersionRaw, Version, guess_version
1010
from ._types import StrOrFile, IOBase
@@ -41,6 +41,8 @@ class Meta:
4141
A title for the pin.
4242
description:
4343
A detailed description of the pin contents.
44+
tags:
45+
Optional tags applied to the pin.
4446
created:
4547
Datetime the pin was created (TODO: document format).
4648
pin_hash:
@@ -63,6 +65,8 @@ class Meta:
6365
6466
"""
6567

68+
_excluded: ClassVar["set[str]"] = {"name", "version", "local"}
69+
6670
title: Optional[str]
6771
description: Optional[str]
6872

@@ -82,10 +86,24 @@ class Meta:
8286
# pin_hash, created, etc.."
8387
version: VersionRaw
8488

89+
tags: Optional[List[str]] = None
8590
name: Optional[str] = None
8691
user: Mapping = field(default_factory=dict)
8792
local: Mapping = field(default_factory=dict)
8893

94+
unknown_fields: InitVar["dict | None"] = None
95+
96+
def __post_init__(self, unknown_fields: "dict | None"):
97+
unknown_fields = {} if unknown_fields is None else unknown_fields
98+
99+
self._unknown_fields = unknown_fields
100+
101+
def __getattr__(self, k):
102+
try:
103+
return self._unknown_fields[k]
104+
except KeyError:
105+
raise AttributeError(f"No metadata field not found: {k}")
106+
89107
def to_dict(self) -> Mapping:
90108
data = asdict(self)
91109

@@ -94,21 +112,37 @@ def to_dict(self) -> Mapping:
94112
def to_pin_dict(self):
95113
d = self.to_dict()
96114

97-
del d["name"]
98-
del d["version"]
99-
del d["local"]
115+
for k in self._excluded:
116+
del d[k]
117+
118+
# TODO: once tag writing is implemented, delete this line
119+
del d["tags"]
100120

101121
return d
102122

103123
@classmethod
104124
def from_pin_dict(cls, data, pin_name, version, local=None) -> "Meta":
105-
106125
# TODO: re-arrange Meta argument positions to reflect what's been
107126
# learned about default arguments. e.g. title was not used at some
108127
# point in api_version 1
128+
all_field_names = {entry.name for entry in fields(Meta)}
129+
130+
keep_fields = all_field_names - cls._excluded
131+
109132
extra = {"title": None} if "title" not in data else {}
110133
local = {} if local is None else local
111-
return cls(**data, **extra, name=pin_name, version=version, local=local)
134+
135+
meta_data = {k: v for k, v in data.items() if k in keep_fields}
136+
unknown = {k: v for k, v in data.items() if k not in keep_fields}
137+
138+
return cls(
139+
**meta_data,
140+
**extra,
141+
name=pin_name,
142+
version=version,
143+
local=local,
144+
unknown_fields=unknown,
145+
)
112146

113147
def to_pin_yaml(self, f: Optional[IOBase] = None) -> "str | None":
114148
data = self.to_pin_dict()

pins/tests/conftest.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
PATH_TO_EXAMPLE_VERSION = PATH_TO_EXAMPLE_BOARD / "df_csv/20220214T163720Z-9bfad/"
1313
EXAMPLE_PIN_NAME = "df_csv"
1414

15+
PATH_TO_MANIFEST_BOARD = files("pins") / "tests/pin-board"
1516

1617
# Based on https://github.com/machow/siuba/blob/main/siuba/tests/helpers.py
1718
BACKEND_MARKS = ["fs_s3", "fs_file", "fs_gcs", "fs_abfs", "fs_rsc"]

pins/tests/pin-board/_pins.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
x:
2+
- x/20221215T180351Z-c3943/
3+
'y':
4+
- y/20221215T180357Z-9ae7a/
5+
- y/20221215T180400Z-b81d5/
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
file: x.json
2+
file_size: 23
3+
pin_hash: c3943ca5a9aab2df
4+
type: json
5+
title: 'x: a pinned integer vector'
6+
description: ~
7+
tags: ~
8+
created: 20221215T180351Z
9+
api_version: 1.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[1,2,3,4,5,6,7,8,9,10]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
file: y.rds
2+
file_size: 61
3+
pin_hash: 9ae7a970010c84e0
4+
type: rds
5+
title: 'y: a pinned integer vector'
6+
description: ~
7+
tags: ~
8+
created: 20221215T180357Z
9+
api_version: 1.0
61 Bytes
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
file: y.json
2+
file_size: 53
3+
pin_hash: b81d5bea9e760608
4+
type: json
5+
title: 'y: a pinned integer vector'
6+
description: ~
7+
tags: ~
8+
created: 20221215T180400Z
9+
api_version: 1.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

0 commit comments

Comments
 (0)