2929
3030import yaml
3131from strictyaml import YAML , StrictYAMLError , YAMLValidationError , load
32- from strictyaml .ruamel .comments import CommentedMap
32+ from strictyaml .ruamel .comments import CommentedMap , CommentedSeq
3333from strictyaml .ruamel .error import CommentMark
3434from strictyaml .ruamel .scalarstring import SingleQuotedScalarString
3535from strictyaml .ruamel .tokens import CommentToken
@@ -150,8 +150,12 @@ class ManifestDict(TypedDict, total=True): # pylint: disable=too-many-ancestors
150150
151151 version : int | str
152152 remotes : NotRequired [Sequence [RemoteDict | Remote ]]
153- projects : Sequence [
154- ProjectEntryDict | ProjectEntry | dict [str , str | list [str ] | dict [str , str ]]
153+ projects : NotRequired [
154+ Sequence [
155+ ProjectEntryDict
156+ | ProjectEntry
157+ | dict [str , str | list [str ] | dict [str , str ]]
158+ ]
155159 ]
156160
157161
@@ -179,7 +183,7 @@ def __init__(
179183 """Create the manifest."""
180184 manifest_data = self ._initialize_basic_attributes (doc , path )
181185 remotes_raw = manifest_data .get ("remotes" , [])
182- projects_raw = manifest_data [ "projects" ]
186+ projects_raw = manifest_data . get ( "projects" , [])
183187 self ._validate_manifest_data (remotes_raw , projects_raw )
184188 self ._setup_default_remote (remotes_raw )
185189 # Re-apply quoting to scalars whose style was stripped by strictyaml.
@@ -355,8 +359,10 @@ def version(self) -> str:
355359 @property
356360 def projects (self ) -> Sequence [ProjectEntry ]:
357361 """Get a list of Projects from the manifest."""
358- projects_mu = self ._doc ["manifest" ]["projects" ].as_marked_up ()
359- return list (self ._build_projects (projects_mu ).values ())
362+ manifest_mu = self ._doc ["manifest" ].as_marked_up ()
363+ if "projects" not in manifest_mu :
364+ return []
365+ return list (self ._build_projects (manifest_mu ["projects" ]).values ())
360366
361367 @staticmethod
362368 def _filter_projects (
@@ -385,14 +391,18 @@ def selected_projects(self, names: Sequence[str]) -> Sequence[ProjectEntry]:
385391
386392 def _find_doc_project (self , name : str ) -> Any | None :
387393 """Return the raw YAML mapping for the project with *name*, or None."""
388- for project in self ._doc ["manifest" ]["projects" ].as_marked_up ():
394+ manifest_mu = self ._doc ["manifest" ].as_marked_up ()
395+ for project in manifest_mu .get ("projects" , []):
389396 if project ["name" ] == name :
390397 return project
391398 return None
392399
393400 def remove (self , project_name : str ) -> None :
394401 """Remove a project from the manifest."""
395- doc_projects = self ._doc ["manifest" ]["projects" ].as_marked_up ()
402+ manifest_mu = self ._doc ["manifest" ].as_marked_up ()
403+ doc_projects = manifest_mu .get ("projects" )
404+ if doc_projects is None :
405+ raise RequestedProjectNotFoundError ([project_name ], [])
396406 names = [p ["name" ] for p in doc_projects ]
397407 try :
398408 del doc_projects [names .index (project_name )]
@@ -469,7 +479,10 @@ def append_project_entry(self, project_entry: "ProjectEntry") -> None:
469479 document (2-space indent under ``projects:``). Call
470480 :meth:`dump` afterwards to persist the change to disk.
471481 """
472- projects_mu = self ._doc ["manifest" ]["projects" ].as_marked_up ()
482+ manifest_mu = self ._doc ["manifest" ].as_marked_up ()
483+ if "projects" not in manifest_mu :
484+ manifest_mu ["projects" ] = CommentedSeq ()
485+ projects_mu = manifest_mu ["projects" ]
473486 projects_mu .append (CommentedMap (project_entry .as_yaml ()))
474487 idx = len (projects_mu ) - 1
475488 projects_mu .ca .items [idx ] = [
@@ -483,12 +496,10 @@ def update_project_version(self, project: ProjectEntry) -> None:
483496 """Update a project's version in the manifest in-place, preserving layout, comments, and line endings."""
484497 p = self ._find_doc_project (project .name )
485498 if p is None :
499+ manifest_mu = self ._doc ["manifest" ].as_marked_up ()
486500 raise RequestedProjectNotFoundError (
487501 [project .name ],
488- [
489- proj ["name" ]
490- for proj in self ._doc ["manifest" ]["projects" ].as_marked_up ()
491- ],
502+ [proj ["name" ] for proj in manifest_mu .get ("projects" , [])],
492503 )
493504 mu = p
494505 insert_pos = 1 # right after 'name:' for any newly added key
0 commit comments