1+ from typing import ClassVar
12from dataclasses import dataclass , asdict , field
23
34import yaml
@@ -24,8 +25,9 @@ class MetaRaw:
2425 The type of pin data stored. This is used to determine how to read / write it.
2526 """
2627
27- file : Union [ str , Sequence [str ]]
28+ file : " str | Sequence[str] | None"
2829 type : str
30+ name : str
2931
3032
3133@dataclass
@@ -57,7 +59,7 @@ class Meta:
5759
5860 """
5961
60- title : str
62+ title : Optional [ str ]
6163 description : Optional [str ]
6264
6365 # TODO(defer): different from R pins, which has a local field
@@ -93,19 +95,58 @@ def to_pin_dict(self):
9395 @classmethod
9496 def from_pin_dict (cls , data , pin_name , version ) -> "Meta" :
9597
96- # version_fields = {"created", "pin_hash"}
97-
98- # #get items necessary for re-creating meta data
99- # meta_data = {k: v for k, v in data.items() if k not in version_fields}
100- # version = version_cls.from_meta_fields(data["created"], data["pin_hash"])
101- return cls (** data , name = pin_name , version = version )
98+ # TODO: re-arrange Meta argument positions to reflect what's been
99+ # learned about default arguments. e.g. title was not used at some
100+ # point in api_version 1
101+ extra = {"title" : None } if "title" not in data else {}
102+ return cls (** data , ** extra , name = pin_name , version = version )
102103
103104 def to_pin_yaml (self , f : Optional [IOBase ] = None ) -> "str | None" :
104105 data = self .to_pin_dict ()
105106
106107 return yaml .dump (data , f )
107108
108109
110+ @dataclass
111+ class MetaV0 :
112+ file : Union [str , Sequence [str ]]
113+ type : str
114+
115+ description : str
116+ name : str
117+
118+ version : VersionRaw
119+
120+ # holds raw data.txt contents
121+ original_fields : dict = field (default_factory = dict )
122+ user : dict = field (default_factory = dict , init = False )
123+
124+ title : ClassVar [None ] = None
125+ created : ClassVar [None ] = None
126+ pin_hash : ClassVar [None ] = None
127+ file_size : ClassVar [None ] = None
128+ api_version : ClassVar [None ] = None
129+
130+ def to_dict (self ):
131+ return asdict (self )
132+
133+ @classmethod
134+ def from_pin_dict (cls , data , pin_name , version ) -> "MetaV0" :
135+ # could infer from dataclasses.fields(), but seems excessive.
136+ req_fields = {"type" , "description" , "name" }
137+
138+ req_inputs = {k : v for k , v in data .items () if k in req_fields }
139+ req_inputs ["file" ] = data ["path" ]
140+
141+ return cls (** req_inputs , name = pin_name , original_fields = data , version = version )
142+
143+ def to_pin_dict (self ):
144+ raise NotImplementedError ("v0 pins metadata are read only." )
145+
146+ def to_pin_yaml (self , * args , ** kwargs ):
147+ self .to_pin_dict ()
148+
149+
109150class MetaFactory :
110151 """Responsible for creating and loading (e.g. from yaml) of meta objects.
111152
@@ -168,8 +209,8 @@ def create(
168209 version = version ,
169210 )
170211
171- def create_raw (self , files : Sequence [StrOrFile ], type : str = "file" , ) -> MetaRaw :
172- return MetaRaw (files , type )
212+ def create_raw (self , files : Sequence [StrOrFile ], type : str , name : str ) -> MetaRaw :
213+ return MetaRaw (files , type , name )
173214
174215 def read_pin_yaml (
175216 self , f : IOBase , pin_name : str , version : "str | VersionRaw"
@@ -181,4 +222,14 @@ def read_pin_yaml(
181222
182223 data = yaml .safe_load (f )
183224
184- return Meta .from_pin_dict (data , pin_name , version = version_obj )
225+ api_version = data .get ("api_version" , 0 )
226+ if api_version >= 2 :
227+ raise NotImplementedError (
228+ f"api_version { api_version } by this version of the pins library"
229+ )
230+ elif api_version == 0 :
231+ cls_meta = MetaV0
232+ else :
233+ cls_meta = Meta
234+
235+ return cls_meta .from_pin_dict (data , pin_name , version = version_obj )
0 commit comments