@@ -143,6 +143,11 @@ def create(self, draft, scheme, identifier=None, provider_name=None):
143143 """
144144 provider = self ._get_provider (scheme , provider_name )
145145 pid_attrs = {}
146+ # Extract prefix from existing PID metadata if available
147+ prefix = (
148+ draft .pids .get (scheme , {}).get ("prefix" ) if draft .pids .get (scheme ) else None
149+ )
150+
146151 if identifier is not None :
147152 try :
148153 pid = provider .get (identifier )
@@ -157,7 +162,9 @@ def create(self, draft, scheme, identifier=None, provider_name=None):
157162 )
158163 pid_attrs = {"identifier" : identifier , "provider" : provider .name }
159164 else :
160- if draft .pids .get (scheme ):
165+ # Only raise error if an identifier already exists
166+ # PIDs with only provider/prefix (without identifier) are incomplete and should be allowed
167+ if draft .pids .get (scheme , {}).get ("identifier" ):
161168 raise ValidationError (
162169 message = _ ("A PID already exists for type {scheme}" ).format (
163170 scheme = scheme
@@ -169,7 +176,11 @@ def create(self, draft, scheme, identifier=None, provider_name=None):
169176 message = _ ("External identifier value is required." ),
170177 field_name = f"pids.{ scheme } " ,
171178 )
172- pid = provider .create (draft )
179+ # Generate ID with optional prefix override
180+ pid_kwargs = {}
181+ if prefix :
182+ pid_kwargs ["prefix" ] = prefix
183+ pid = provider .create (draft , ** pid_kwargs )
173184 pid_attrs = {"identifier" : pid .pid_value , "provider" : provider .name }
174185
175186 if provider .client : # provider and identifier already in dict
@@ -183,16 +194,42 @@ def create_all(self, draft, pids=None, schemes=None):
183194
184195 # Create with an identifier value provided
185196 for scheme , pid_attrs in (pids or {}).items ():
197+ # Temporarily store prefix in draft.pids for create() to read
198+ prefix = pid_attrs .get ("prefix" )
199+ if prefix :
200+ if scheme not in draft .pids :
201+ draft .pids [scheme ] = {"prefix" : prefix }
202+ elif "prefix" not in draft .pids [scheme ]:
203+ draft .pids [scheme ]["prefix" ] = prefix
204+
186205 result [scheme ] = self .create (
187206 draft ,
188207 scheme ,
189- pid_attrs [ "identifier" ] ,
208+ pid_attrs . get ( "identifier" ) ,
190209 pid_attrs .get ("provider" ),
191210 )
192211
193212 # Create without an identifier value provided (only the scheme)
213+ # Use provider and prefix from pids dict if available
194214 for scheme in schemes or []:
195- result [scheme ] = self .create (draft , scheme )
215+ pid_attrs = (pids or {}).get (scheme , {})
216+ provider_name = pid_attrs .get ("provider" )
217+
218+ # Temporarily store prefix in draft.pids for create() to read
219+ prefix = pid_attrs .get ("prefix" )
220+ if prefix and scheme not in draft .pids :
221+ draft .pids [scheme ] = {"prefix" : prefix }
222+ elif prefix and scheme in draft .pids :
223+ # Preserve existing prefix if not already set
224+ if "prefix" not in draft .pids [scheme ]:
225+ draft .pids [scheme ]["prefix" ] = prefix
226+
227+ result [scheme ] = self .create (draft , scheme , provider_name = provider_name )
228+
229+ # Strip transient 'prefix' field from results - it's not part of the
230+ # JSON schema and should not be persisted on the record.
231+ for scheme_attrs in result .values ():
232+ scheme_attrs .pop ("prefix" , None )
196233
197234 return result
198235
@@ -247,10 +284,7 @@ def discard(self, scheme, identifier, provider_name=None, soft_delete=False):
247284 if not provider .can_modify (pid ) and not soft_delete :
248285 raise ValidationError (
249286 message = [
250- _ (
251- "Cannot discard a reserved or registered persistent "
252- "identifier."
253- ),
287+ _ ("Cannot discard a reserved or registered persistent identifier." ),
254288 ],
255289 field_name = f"pids.{ scheme } " ,
256290 )
@@ -303,5 +337,5 @@ def create_and_reserve(self, record, **kwargs):
303337 """Create and reserve a PID for the given record, and update the record with the reserved PID."""
304338 pids = record .get ("pids" , {})
305339 provider_pid_dicts = self ._get_providers (pids )
306- for provider , _ in provider_pid_dicts :
340+ for provider , pid_dict in provider_pid_dicts :
307341 provider .create_and_reserve (record )
0 commit comments