Skip to content

link.project

Project()

Bases: Data

Representation of a Bip project.

Projects are defined by ProjectModels, which define a set of rules and behaviours for the Project. For example the model controls the naming convention.

Info

This class inherits from Data, like Item, Document and Version, since they share similar behaviour. See bip.link.data.Data for inherited methods.

Attributes:

Name Type Description
uid str

Bip unique identifier (uuid4). Edition is forbidden if this is an persistent (saved) entity.

slug str

Human-readable unique identifier, namespaced in the parent model scope.

name str

Name of the project.

model ProjectModel

Bip project model object.

number int

Project identifier.

description str

Short description of the project.

folder_name str

Folder name for path generation.

active bool

If True, the project is active and visible in most tools by defaults,

tracker str

Identifier of the production tracker used for the project.

tracker_sync bool

If True, the Project is synchronized with the foreign tracker.

tracker_primary bool

If tracker_sync is True, determines if Bip is the primary data emitter (True) or if it is replicating the foreign tracker data (False).

Source code in client/bip/link/project.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def __init__(self):
    super(Project, self).__init__()
    self.uid: str = ""
    self.slug: str = ""
    self.name: str = ""

    self.model = ProjectModel

    # General
    self.number: int = 0
    self.description: str = ""
    self.folder_name: str = ""
    self.code: str = ""
    self.active: bool = True

    # Tracker settings
    self._tracking_direction: str = ""  # FROM_BIP or TO_BIP
    self._tracking_sync: bool = False
    self._tracking_product: str = ""

    # Config
    self.lock_meta_model = True

    # Helpers
    self._groups = []
    self._meta_model = None
    self._project = self

children_count: int property

Number of Items parented to the Project.

Returns:

Name Type Description
int int

Item count.

has_children: bool property

Does the Project have Items.

Returns:

Name Type Description
bool bool

True if the Project has Items, False otherwise.

path: str property

Dynamic path of the project directory.

The path is dynamically generated by the running Bip client, based on the working directory.

Warning

The path may differ from a machine to another since the path uses the working_directory local setting, which might vary between machines, depending on the client config.

Returns:

Name Type Description
str str

Path of the project directory.

delete(safe=True)

Deletes the Project.

By default, if the Project has Items parented to it, the deletion won't be accepted, unless safe is set to True.

Deleting the Project deletes any downstream entity: Item, ItemModel, Document, DocumentModel, Version, Group, GroupModel, Task, TaskModel, Definition and Attribute.

Parameters:

Name Type Description Default
safe bool

bool: Prevents the deletion if the Project has children (Items) (Default value = True)

True

Raises:

Type Description
ValueError

If safe is True and the Project has children.

Source code in client/bip/link/project.py
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
@permission("delete_project")
def delete(self, safe: bool = True):
    """Deletes the Project.

    By default, if the Project has Items parented to it, the deletion won't be accepted,
    unless `safe` is set to True.

    Deleting the Project deletes any downstream entity: Item, ItemModel, Document,
    DocumentModel, Version, Group, GroupModel, Task, TaskModel, Definition and Attribute.

    Args:
      safe: bool: Prevents the deletion if the Project has children (Items) (Default value = True)

    Raises:
        ValueError: If safe is True and the Project has children.
    """
    if safe and self.has_children:
        raise ValueError(
            f"Impossible to safely delete {self}. The item has children."
        )

    return sink.project.delete(self.to_dict())

generate(name, meta_model, slug=None, model=None, groups=(), auto_save=True, **kwargs) classmethod

Generates a Project object.

The data model of the new Project must be passing the validation in link.model.validate()

By default, the generated Project is saved straight after creation. In some cases, it can be useful to get the floating (not recorded on the database) object in order to perform further operation, and save after that. That can be achieved by setting auto_save to False.

Parameters:

Name Type Description Default
name str

str: Name of the new project.

required
meta_model MetaModel

MetaModel: Special dictionary defining the data-model for the new Project.

required
slug Optional[str]

Optional[str]: Slug of the new project (Default value = None)

None
model Optional[Union[ProjectModel, str]]

Optional[Union[ProjectModel, str]]: Model of the new project. Can be left to None if the Bip instance

None
groups Union[List, Tuple]

Union[List, Tuple]: If the ProjectModel has required_memberships, list of the

()
auto_save bool

bool: If True, the returned object is saved. Otherwise it is floating. (Default value = True)

True
**kwargs

Any non-mandatory valid attribute of Project can be passed.

{}

Raises:

Type Description
ValueError

Failed validation, if auto_save is True.

TypeError

Failed validation, if auto_save is True.

Returns:

Name Type Description
Project Project

Saved generated Project.

Source code in client/bip/link/project.py
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
@classmethod
@permission("create_project")
def generate(
    cls,
    name: str,
    meta_model: MetaModel,
    slug: Optional[str] = None,
    model: Optional[Union[ProjectModel, str]] = None,
    groups: Union[List, Tuple] = (),
    auto_save: bool = True,
    **kwargs,
) -> Project:
    """Generates a Project object.

    The data model of the new Project must be passing the validation in `link.model.validate()`

    By default, the generated Project is saved straight after creation. In some cases, it can be useful to get the
    floating (not recorded on the database) object in order to perform further operation, and save after that.
    That can be achieved by setting `auto_save` to False.

    Args:
      name: str: Name of the new project.
      meta_model: MetaModel: Special dictionary defining the data-model for the new Project.
      slug: Optional[str]: Slug of the new project (Default value = None)
      model: Optional[Union[ProjectModel, str]]: Model of the new project. Can be left to None if the Bip instance
      has a `default_project_model` (see `link.config`), or can be the string of a ProjectModel slug (Default value = None)
      groups: Union[List, Tuple]: If the ProjectModel has required_memberships, list of the
      mandatory groups (Default value = ())
      auto_save: bool: If True, the returned object is saved. Otherwise it is floating. (Default value = True)
      **kwargs: Any non-mandatory valid attribute of Project can be passed.

    Raises:
        ValueError: Failed validation, if auto_save is True.
        TypeError: Failed validation, if auto_save is True.

    Returns:
        Project: Saved generated Project.
    """
    if isinstance(model, str):
        name = model
        model = get_model(slug=model)
        if not model:
            raise ValueError(f"No ProjectModel with the slug {name} found. ")

    if not model:
        model = get_default_project_model()
        if not model:
            raise ValueError(
                "There is no default ProjectModel set for this server, "
                "you must specify one manually."
            )

    project = cls()
    project.name = name
    project._meta_model = meta_model
    project.slug = slug
    project.model = model

    if groups:
        project._groups = groups

    # Add optional attributes
    project._add_dynamic_attributes(**kwargs)

    if not project.folder_name:
        project.folder_name = string_cleaner(name, sep="_")

    if not project.code:
        project.code = string_cleaner(name, sep="_")

    if auto_save:
        project.save()

    return project

get(slug=None, uid=None, model=None, open_only=False) classmethod

Get a specific Project or all Projects from a ProjectModel or all Projects.

It is possible to get a specific Project from its uid or its slug. When providing one, the other can be left to None. If none of these two parameters are specified, The getter becomes a global getter and returns a collection of Projects.

If searching by slug, and if the Bip server does not have a default ProjectModel set, the ProjectModel must be provided in model, either its slug or the ProjectModel object. This is because Projects slugs are namespaced, and the namespace scope is per ProjectModel.

To get all Projects, from all ProjectModels, all the arguments must be left to None.

Parameters:

Name Type Description Default
slug Optional[str]

Optional[str]: Slug of a Project. If specified, uid can be left blank. (Default value = None)

None
uid Optional[str]

Optional[str]: Uid of a Project. If specified, slug can be left blank. (Default value = None)

None
model Optional[Union[ProjectModel, str]]

Optional[Union[ProjectModel]]: If searching by slug, must be provided. It can be a ProjectModel or the slug of a ProjectModel (Default value = None)

None
open_only bool

bool: If True, only active Projects are returned (Default value = False)

False

Raises:

Type Description
TypeError

An argument has an unexpected type.

LookupError

No matching ProjectModel found.

Returns:

Type Description
Union[Project, List[Project]]
  • list: Collection of Projects, if no uid or slug specified.
Union[Project, List[Project]]
  • Project: Single Project if a uid or a slug has been specified.
Source code in client/bip/link/project.py
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
@classmethod
@permission("read_project")
def get(
    cls,
    slug: Optional[str] = None,
    uid: Optional[str] = None,
    model: Optional[Union[ProjectModel, str]] = None,
    open_only: bool = False,
) -> Union[Project, List[Project]]:
    """Get a specific Project or all Projects from a ProjectModel or all Projects.

    It is possible to get a specific Project from its `uid` or its `slug`.
    When providing one, the other can be left to None. If none of these two parameters are specified,
    The getter becomes a global getter and returns a collection of Projects.

    If searching by slug, and if the Bip server does not have a default ProjectModel set,
    the ProjectModel must be provided in `model`, either its slug or the ProjectModel object.
    This is because Projects slugs are namespaced, and the namespace scope is per ProjectModel.

    To get all Projects, from all ProjectModels, all the arguments must be left to None.

    Args:
        slug: Optional[str]: Slug of a Project. If specified, `uid` can be left blank. (Default value = None)
        uid: Optional[str]: Uid of a Project. If specified, `slug` can be left blank. (Default value = None)
        model: Optional[Union[ProjectModel]]: If searching by slug, must be provided.
            It can be a ProjectModel or the slug of a ProjectModel (Default value = None)
        open_only: bool: If True, only active Projects are returned (Default value = False)

    Raises:
        TypeError: An argument has an unexpected type.
        LookupError: No matching ProjectModel found.

    Returns:
        - list: Collection of Projects, if no uid or slug specified.
        - Project: Single Project if a uid or a slug has been specified.
    """
    if isinstance(model, str):
        name = model
        model = get_model(slug=model)
        if not model:
            raise ValueError(f"No ProjectModel with the slug {name} found. ")

    if slug and not model:
        model = get_default_project_model()
        if not model:
            raise ValueError(
                "If searching by slug and no default ProjectModel is set, "
                "you must specify a model manually."
            )

    if model:
        model = model.to_dict()

    if uid or slug:
        result = sink.project.get_project(slug, uid, model)
        if result:
            return cls.from_dict(result)
    else:
        projects = sink.project.get_projects(model)  # model can be None
        projects = [cls.from_dict(u) for u in projects]
        projects = sorted(projects, key=lambda k: k.name)

        if open_only:
            return [p for p in projects if p.active]
        else:
            return projects

get_all_definitions()

Convenient class implementation of: bip.link.attribute.get_all_definitions.

Info

This method returns all the Project Definitions. For getting only the Definitions that are compatible with the Project entity, get_definitions() must be used.

Warning

The signature of Project.get_all_definitions() and bip.link.attribute.get_all_definitions are different since Project.get_all_definitions() passes itself to the function as project=self.

Source code in client/bip/link/project.py
424
425
426
427
428
429
430
431
432
433
434
435
def get_all_definitions(self) -> List[Definition]:
    """Convenient class implementation of: `bip.link.attribute.get_all_definitions`.

    !!! info
        This method returns all the Project Definitions.
        For getting only the Definitions that are compatible with the Project entity, `get_definitions()` must be used.

    !!! warning
        The signature of `Project.get_all_definitions()` and `bip.link.attribute.get_all_definitions`
        are different since `Project.get_all_definitions()` passes itself to the function as `project=self`.
    """
    return _attribute.get_definitions(self)

get_children(model=None)

Convenient alias for get_items()

Source code in client/bip/link/project.py
351
352
353
def get_children(self, model: Optional[Union[ItemModel, str]] = None) -> List[Item]:
    """Convenient alias for `get_items()`"""
    return self.get_items(model)

get_document_model(slug=None, uid=None)

Convenient class implementation of: bip.link.document.get_model.

Warning

The signature of Project.get_document_model() and bip.link.document.get_model are different since Project.get_document_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
453
454
455
456
457
458
459
460
461
462
def get_document_model(
    self, slug: Optional[str] = None, uid: Optional[str] = None
) -> DocumentModel:
    """Convenient class implementation of: `bip.link.document.get_model`.

    !!! warning
        The signature of `Project.get_document_model()` and `bip.link.document.get_model`
        are different since `Project.get_document_model()` passes itself to the function as `project=self`.
    """
    return _document.get_model(self, slug, uid)

get_document_models()

Convenient class implementation of: bip.link.document.get_models.

Warning

The signature of Project.get_document_models() and bip.link.document.get_models are different since Project.get_document_models() passes itself to the function as project=self.

Source code in client/bip/link/project.py
464
465
466
467
468
469
470
471
def get_document_models(self) -> List[DocumentModel]:
    """Convenient class implementation of: `bip.link.document.get_models`.

    !!! warning
        The signature of `Project.get_document_models()` and `bip.link.document.get_models`
        are different since `Project.get_document_models()` passes itself to the function as `project=self`.
    """
    return _document.get_models(self)

get_group_model(slug=None, uid=None)

Convenient class implementation of: bip.link.group.get_model.

Warning

The signature of Project.get_group_model() and bip.link.group.get_model() are different since Project.get_group_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
388
389
390
391
392
393
394
395
396
397
def get_group_model(
    self, slug: Optional[str] = None, uid: Optional[str] = None
) -> GroupModel:
    """Convenient class implementation of: `bip.link.group.get_model`.

    !!! warning
        The signature of `Project.get_group_model()` and `bip.link.group.get_model()`
        are different since `Project.get_group_model()` passes itself to the function as `project=self`.
    """
    return _group.get_model(slug, uid, project=self)

get_group_models()

Convenient class implementation of: bip.link.group.get_models.

Warning

The signature of Project.get_group_models() and bip.link.group.get_models() are different since Project.get_group_models() passes itself to the function as project=self.

Source code in client/bip/link/project.py
399
400
401
402
403
404
405
406
def get_group_models(self) -> List[GroupModel]:
    """Convenient class implementation of: `bip.link.group.get_models`.

    !!! warning
        The signature of `Project.get_group_models()` and `bip.link.group.get_models()`
        are different since `Project.get_group_models()` passes itself to the function as `project=self`.
    """
    return _group.get_models(self)

get_item(model=None, slug=None, uid=None, group=None)

Get a specific Item.

There are two different ways to get an item: - From its uid only. No other argument is required then, since uid are unique to the whole Bip server. - From its slug. In this case, the ItemModel must be provided, either its slug or the ItemModel object. This is because Items are namespaced, and the namespace scope is per ItemModel. If the ItemModel has a uniqueness scope (which means the names are unique within a Group scope), the group must be provided, either its slug or the Group object.

Examples:

# By slug
example_project.get_item(model="asset", slug="john-doe")

# By uid
example_project.get_item(uid="46c12269-d5d9-40fb-8554-ed1dd9b46422")

# By slug with namespace group
example_project.get_item(model="shot", slug="sh0100", group="seq10")

Parameters:

Name Type Description Default
slug Optional[str]

Optional[str]: Slug of the searched Item. If providing, then uid can be left to None, but model

None
uid Optional[str]

Optional[str]: Uid of the searched Item. If provided, no other argument needs to be provided.

None
model Optional[Union[ItemModel, str]]

Optional[Union[ItemModel, str]]: ItemModel (object or slug) of the searched Item,

None
group Optional[Union[Group, str]]

Optional[Union[GroupModel, str]]: If the found ItemModel has a uniqueness scope, the Group

None

Raises:

Type Description
TypeError

An argument has an unexpected type.

LookupError

No matching GroupModel or Group found.

Returns:

Name Type Description
Item Item

Matched Item.

Source code in client/bip/link/project.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
def get_item(
    self,
    model: Optional[Union[ItemModel, str]] = None,
    slug: Optional[str] = None,
    uid: Optional[str] = None,
    group: Optional[Union[Group, str]] = None,
) -> Item:
    """Get a specific Item.

    There are two different ways to get an item:
    - From its **uid** only. No other argument is required then, since uid are unique to the whole Bip server.
    - From its **slug**. In this case, the ItemModel must be provided, either its slug or the ItemModel object.
    This is because Items are namespaced, and the namespace scope is per ItemModel.
    If the ItemModel has a uniqueness scope (which means the names are unique within a Group scope),
    the group must be provided, either its slug or the Group object.

    Examples:
        ```python
        # By slug
        example_project.get_item(model="asset", slug="john-doe")

        # By uid
        example_project.get_item(uid="46c12269-d5d9-40fb-8554-ed1dd9b46422")

        # By slug with namespace group
        example_project.get_item(model="shot", slug="sh0100", group="seq10")
        ```

    Args:
      slug: Optional[str]: Slug of the searched Item. If providing, then `uid` can be left to None, but `model`
      must be provided. (Default value = None)
      uid: Optional[str]: Uid of the searched Item. If provided, no other argument needs to be provided.
      (Default value = None)
      model: Optional[Union[ItemModel, str]]: ItemModel (object or slug) of the searched Item,
      if searching by slug. (Default value = None)
      group: Optional[Union[GroupModel, str]]: If the found ItemModel has a uniqueness scope, the Group
      (object or slug) must be provided (Default value = None)

    Raises:
        TypeError: An argument has an unexpected type.
        LookupError: No matching GroupModel or Group found.

    Returns:
        Item: Matched Item.
    """

    if uid:
        return _item.get_from_project(self, uid)
    elif slug and model:
        if isinstance(model, str):
            model = self.get_item_model(slug=model)
        return _item.get_item(model, slug, None, group)
    else:
        raise ValueError("A uid must be provided, or a slug and a model.")

get_item_by_slug(slug, model_slug, group_slug=None)

Get a specific Item by slugs.

Useful for debugging.

This is a convenient method that does exactly what get_item() does, but only with slugs. Since get_item() allows different ways to query an Item, the parameters must be explicitly specified. In some cases, for manual scripts or debugging, it can be quicker or more readable to use this method.

Examples

example_project.get_item(slug="sh0100", model="shot", group="seq10")
# becomes this:
example_project.get_item_by_slug("sh0100", "shot", "seq10")

Parameters:

Name Type Description Default
slug str

str: Slug of the searched Item.

required
model_slug str

str: Slug of the ItemModel of searched Item.

required
group_slug Optional[str]

Optional[str]: (Default value = None)

None

Raises:

Type Description
LookupError

No matching Item found.

Returns:

Name Type Description
Item Item

Matching Item.

Source code in client/bip/link/project.py
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
def get_item_by_slug(
    self, slug: str, model_slug: str, group_slug: Optional[str] = None
) -> Item:
    """Get a specific Item by slugs.

    Useful for debugging.

    This is a convenient method that does exactly what `get_item()` does, but only with slugs.
    Since `get_item()` allows different ways to query an Item, the parameters must be explicitly specified.
    In some cases, for manual scripts or debugging, it can be quicker or more readable to use this method.

    Examples
        ```python
        example_project.get_item(slug="sh0100", model="shot", group="seq10")
        # becomes this:
        example_project.get_item_by_slug("sh0100", "shot", "seq10")
        ```

    Args:
      slug: str: Slug of the searched Item.
      model_slug: str: Slug of the ItemModel of searched Item.
      group_slug: Optional[str]:  (Default value = None)

    Raises:
        LookupError: No matching Item found.

    Returns:
        Item: Matching Item.
    """
    return self.get_item(model=model_slug, slug=slug, group=group_slug)

get_item_model(slug=None, uid=None)

Convenient class implementation of: bip.link.item.get_model.

Warning

The signature of Project.get_item_model() and bip.link.group.get_model() are different since Project.get_item_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
355
356
357
358
359
360
361
362
363
364
def get_item_model(
    self, slug: Optional[str] = None, uid: Optional[str] = None
) -> Union[ItemModel, List[ItemModel]]:
    """Convenient class implementation of: `bip.link.item.get_model`.

    !!! warning
        The signature of `Project.get_item_model()` and `bip.link.group.get_model()`
        are different since `Project.get_item_model()` passes itself to the function as `project=self`.
    """
    return _item.get_model(self, slug, uid)

get_item_models()

Convenient class implementation of: bip.link.item.get_models.

Warning

The signature of Project.get_item_models() and bip.link.group.get_models() are different since Project.get_item_models() passes itself to the function as project=self.

Source code in client/bip/link/project.py
366
367
368
369
370
371
372
373
def get_item_models(self) -> List[ItemModel]:
    """Convenient class implementation of: `bip.link.item.get_models`.

    !!! warning
        The signature of `Project.get_item_models()` and `bip.link.group.get_models()`
        are different since `Project.get_item_models()` passes itself to the function as `project=self`.
    """
    return _item.get_models(self)

get_items(model=None)

Get Items from an ItemModel or all Items of the Project.

If model is not specified, this method returns the Items from all ItemModels found for the Project, using bip.link.item.get_from_project()

Parameters:

Name Type Description Default
model Optional[Union[ItemModel, str]]

Optional[Union[ItemModel, str]]: ItemModel or slug. (Default value = None)

None

Returns: list: Collection of Items.

Source code in client/bip/link/project.py
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
def get_items(self, model: Optional[Union[ItemModel, str]] = None) -> List[Item]:
    """Get Items from an ItemModel or all Items of the Project.

    If `model` is not specified, this method returns the Items from all
    ItemModels found for the Project, using `bip.link.item.get_from_project()`

    Args:
      model: Optional[Union[ItemModel, str]]: ItemModel or slug. (Default value = None)
    Returns:
        list: Collection of Items.
    """
    if model:
        if isinstance(model, str):
            model = self.get_item_model(slug=model)

        return model.get_items()
    else:
        return _item.get_from_project(self)

get_task_model(slug=None, uid=None)

Convenient class implementation of: bip.link.task.get_model_from_project.

Warning

The signature of Project.get_task_model() and bip.link.task.get_model_from_project are different since Project.get_task_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
482
483
484
485
486
487
488
489
490
491
def get_task_model(
    self, slug: Optional[str] = None, uid: Optional[str] = None
) -> TaskModel:
    """Convenient class implementation of: `bip.link.task.get_model_from_project`.

    !!! warning
        The signature of `Project.get_task_model()` and `bip.link.task.get_model_from_project`
        are different since `Project.get_task_model()` passes itself to the function as `project=self`.
    """
    return _task.get_model_from_project(project=self, slug=slug, uid=uid)

get_task_models()

Convenient class implementation of: bip.link.task.get_models_from_project.

Warning

The signature of Project.get_task_models() and bip.link.task.get_models_from_project are different since Project.get_task_models() passes itself to the function as project=self.

Source code in client/bip/link/project.py
473
474
475
476
477
478
479
480
def get_task_models(self) -> List[TaskModel]:
    """Convenient class implementation of: `bip.link.task.get_models_from_project`.

    !!! warning
        The signature of `Project.get_task_models()` and `bip.link.task.get_models_from_project`
        are different since `Project.get_task_models()` passes itself to the function as `project=self`.
    """
    return _task.get_models_from_project(project=self)

new_definition(name, type, slug=None, auto_save=True, **kwargs)

Convenient class implementation of: bip.link.attribute.new_definition.

Warning

The signature of Project.new_definition() and bip.link.attribute.new_definition are different since Project.new_definition() passes itself to the function as project=self.

Source code in client/bip/link/project.py
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
def new_definition(
    self,
    name: str,
    type: str,
    slug: Optional[str] = None,
    auto_save: bool = True,
    **kwargs,
) -> Definition:
    """Convenient class implementation of: `bip.link.attribute.new_definition`.

    !!! warning
        The signature of `Project.new_definition()` and `bip.link.attribute.new_definition`
        are different since `Project.new_definition()` passes itself to the function as `project=self`.
    """
    return _attribute.new_definition(self, name, type, slug, auto_save, **kwargs)

new_group_model(name, type, slug=None, auto_save=True, **kwargs)

Convenient class implementation of: bip.link.group.new_model.

Warning

The signature of Project.new_group_model() and bip.link.group.new_model() are different since Project.new_group_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
def new_group_model(
    self,
    name: str,
    type: str,
    slug: Optional[str] = None,
    auto_save: bool = True,
    **kwargs,
) -> GroupModel:
    """Convenient class implementation of: `bip.link.group.new_model`.

    !!! warning
        The signature of `Project.new_group_model()` and `bip.link.group.new_model()`
        are different since `Project.new_group_model()` passes itself to the function as `project=self`.
    """
    return _group.new_model(name, type, self, slug, auto_save, **kwargs)

new_item_model(name, slug=None, auto_save=True, **kwargs)

Convenient class implementation of: bip.link.item.new_model.

Warning

The signature of Project.new_item_model() and bip.link.item.new_model() are different since Project.new_item_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
375
376
377
378
379
380
381
382
383
384
385
386
def new_item_model(
    self, name: str, slug: Optional[str] = None, auto_save: bool = True, **kwargs
) -> ItemModel:
    """Convenient class implementation of: `bip.link.item.new_model`.

    !!! warning
        The signature of `Project.new_item_model()` and `bip.link.item.new_model()`
        are different since `Project.new_item_model()` passes itself to the function as `project=self`.
    """
    return _item.new_model(
        name=name, project=self, slug=slug, auto_save=auto_save, **kwargs
    )

new_task_model(name, slug=None, auto_save=True, **kwargs)

Convenient class implementation of: bip.link.task.new_model.

Warning

The signature of Project.new_task_model() and bip.link.task.new_model are different since Project.new_task_model() passes itself to the function as project=self.

Source code in client/bip/link/project.py
493
494
495
496
497
498
499
500
501
502
def new_task_model(
    self, name, slug: Optional[str] = None, auto_save=True, **kwargs
) -> TaskModel:
    """Convenient class implementation of: `bip.link.task.new_model`.

    !!! warning
        The signature of `Project.new_task_model()` and `bip.link.task.new_model`
        are different since `Project.new_task_model()` passes itself to the function as `project=self`.
    """
    return _task.new_model(name, self, slug, auto_save, **kwargs)

save()

Saves the Project to the database.

If the Project is floating, saving makes it persistent.

Attributes changes are not applied to the database at modification. Saving the Project does.

Raises:

Type Description
ValueError

Failed validation.

TypeError

Failed validation.

Source code in client/bip/link/project.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
@permission("edit_project")
def save(self):
    """Saves the Project to the database.

    If the Project is floating, saving makes it persistent.

    Attributes changes are not applied to the database at modification.
    Saving the Project does.

    Raises:
        ValueError: Failed validation.
        TypeError: Failed validation.

    """
    if not self._is_modified and self.uid:
        return

    if not self.uid:
        self._generate_uid()

    self._default()
    self._validate()

    sink.project.save(self.to_dict())

    if self.is_floating:
        self._meta_model.connect(self)

    was_floating = self.is_floating

    self._sink()

    if self._groups and was_floating:
        for group in self._groups:
            self.add_to(group)

    if was_floating:
        self._post_creation()

set_default_document_model(document_model)

Sets the default DocumentModel for this project.

If a default DocumentModel is set for a Project, it is used when creating Documents and not specifying any model.

Parameters:

Name Type Description Default
document_model DocumentModel

DocumentModel: DocumentModel to be set as default.

required

Raises:

Type Description
TypeError

document_model is not a DocumentModel object.

ValueError

document_model is floating (non-persistent)

Source code in client/bip/link/project.py
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
def set_default_document_model(self, document_model: DocumentModel):
    """Sets the default DocumentModel for this project.

    If a default DocumentModel is set for a Project, it is used when creating Documents and not specifying any model.

    Args:
      document_model: DocumentModel: DocumentModel to be set as default.

    Raises:
        TypeError: document_model is not a DocumentModel object.
        ValueError: document_model is floating (non-persistent)
    """
    from .document import DocumentModel

    if not isinstance(document_model, DocumentModel):
        raise TypeError(
            "{} is not a DocumentModel object.".format(str(document_model))
        )

    if document_model.is_floating:
        raise ValueError("document_model must be saved first.")

    sink.project.set_default_document_model(self.to_dict(), document_model.to_dict())

set_default_item_model(item_model)

Sets the default ItemModel for this project.

If a default ItemModel is set for a Project, it is used when creating Items and not specifying any model.

Parameters:

Name Type Description Default
item_model ItemModel

ItemModel: ItemModel to be set as default.

required
Source code in client/bip/link/project.py
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
def set_default_item_model(self, item_model: ItemModel):
    """Sets the default ItemModel for this project.

    If a default ItemModel is set for a Project, it is used when creating Items and not specifying any model.

    Args:
      item_model: ItemModel: ItemModel to be set as default.
    """
    from .item import ItemModel

    if not isinstance(item_model, ItemModel):
        raise TypeError("{} is not a ItemModel object.".format(str(item_model)))

    if item_model.is_floating:
        raise ValueError("item_model must be saved first.")

    sink.project.set_default_item_model(self.to_dict(), item_model.to_dict())

ProjectModel()

Bases: BipObject

Representation of a Bip project model.

The ProjectModel is a template, which sets some rules that any Project modelged with the ProjectModel must follow.

Attributes:

Name Type Description
uid str

Bip unique identifier (uuid4). Edition is forbidden if this is an persistent (saved) entity.

slug str

Human-readable unique identifier.

name str

Name of the model.

plural int

Plural of the name.

folder_name str

Folder name if the model is referenced in a path pattern.

path_pattern str

Path pattern for Projects path generation.

Source code in client/bip/link/project.py
781
782
783
784
785
786
787
788
789
790
791
792
793
def __init__(self):
    super(ProjectModel, self).__init__()
    self.uid: str = ""
    self.slug: str = ""
    self.name: str = ""
    self.plural: str = ""
    self.folder_name: str = ""
    self.code: str = ""
    self.path_pattern: str = ""

    # Helpers
    self._has_required_memberships: bool = False
    self._has_optional_memberships: bool = False

children_count: int property

Number of Projects linked to the ProjectModel.

Returns:

Name Type Description
int int

Project count.

has_children: bool property

Does the ProjectModel have Projects.

Returns:

Name Type Description
bool bool

True if the ProjectModel has Projects, False otherwise.

has_memberships: bool property

Does the ProjectModel has memberships.

Lightweight method avoiding querying the database.

Returns:

Name Type Description
bool bool

True if the ProjectModel has memberships, False otherwise.

has_optional_memberships: bool property

Does the ProjectModel has optional memberships.

Lightweight method avoiding querying the database.

Returns:

Name Type Description
bool bool

True if the ProjectModel has optional memberships, False otherwise.

has_required_memberships: bool property

Does the ProjectModel has required memberships.

Lightweight method avoiding querying the database.

Returns:

Name Type Description
bool bool

True if the ProjectModel requires memberships, False otherwise.

add_membership(group_model, required=True)

Adds a required or optional membership.

Tip

Required or optional memberships are GroupModel that any new Project created with the current ProjectModel must or can be member of in order to be saved.

Parameters:

Name Type Description Default
group_model GroupModel

GroupModel: GroupModel.

required
required

bool

True

Raises:

Type Description
ValueError

Failed validation.

TypeError

Failed validation.

Source code in client/bip/link/project.py
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
def add_membership(self, group_model: GroupModel, required=True):
    """Adds a required or optional membership.

    !!! tip
        Required or optional memberships are GroupModel that any new Project created with the current ProjectModel
        must or can be member of in order to be saved.

    Args:
      group_model: GroupModel: GroupModel.
      required: bool

    Raises:
        ValueError: Failed validation.
        TypeError: Failed validation.
    """
    if self.has_children:
        raise ValueError(
            "This ProjectModel already has instances. You cannot modify its required memberships."
        )

    if not isinstance(group_model, _group.GroupModel):
        raise TypeError("group_model must be a GroupModel object.")

    if group_model.is_floating:
        raise ValueError("group_model must be saved first.")

    if self.has_optional_memberships:
        optional_memberships = self.get_optional_memberships()
        if group_model in optional_memberships:
            raise ValueError(f"{group_model} is already an optional membership.")

    if self.has_required_memberships:
        required_memberships = self.get_required_memberships()
        if group_model in required_memberships:
            raise ValueError(f"{group_model} is already a required membership.")

    _group.add_membership(self, group_model, required)

    if required:
        self._has_required_memberships = True
    else:
        self._has_optional_memberships = True

    self.save()

delete(safe=True)

Deletes the ProjectModel.

By default, if the ProjectModel has Projects parented to it, the deletion won't be accepted, unless safe is set to True.

Deleting the ProjectModel deletes any downstream entity: Project, Item, ItemModel, Document, DocumentModel, Version, Group, GroupModel, Task, TaskModel, Definition and Attribute.

Parameters:

Name Type Description Default
safe bool

bool: Prevents the deletion if the ProjectModel has children (Projects) (Default value = True)

True

Raises:

Type Description
ValueError

If safe is True and the ProjectModel has children.

Source code in client/bip/link/project.py
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
def delete(self, safe: bool = True):
    """Deletes the ProjectModel.

    By default, if the ProjectModel has Projects parented to it, the deletion won't be accepted,
    unless `safe` is set to True.

    Deleting the ProjectModel deletes any downstream entity: Project, Item, ItemModel, Document,
    DocumentModel, Version, Group, GroupModel, Task, TaskModel, Definition and Attribute.

    Args:
      safe: bool: Prevents the deletion if the ProjectModel has children (Projects) (Default value = True)

    Raises:
        ValueError: If safe is True and the ProjectModel has children.
    """
    if safe and self.has_children:
        raise ValueError(
            f"Impossible to safely delete {self}. The ItemModel has children."
        )

    if self.has_children:
        for project in self.get_projects():
            project.delete(safe=False)

    sink.project.delete_model(self.to_dict())

generate(name, path_pattern, auto_save=True, **kwargs) classmethod

Generates a ProjectModel object.

By default, the generated ProjectModel is saved straight after creation. In some cases, it can be useful to get the floating (not recorded on the database) object in order to perform further operation, and save after that. That can be achieved by setting auto_save to False.

Parameters:

Name Type Description Default
name str

str: Name of the new model.

required
path_pattern str

str: Path pattern of the new model.

required
auto_save bool

bool: If True, the returned object is saved. Otherwise it is floating. (Default value = True)

True
**kwargs

Any non-mandatory valid attribute of ProjectModel can be passed.

{}

Raises:

Type Description
ValueError

Failed validation, if auto_save is True.

TypeError

Failed validation, if auto_save is True.

Returns:

Name Type Description
ProjectModel

Generated ProjectModel.

Source code in client/bip/link/project.py
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
@classmethod
def generate(cls, name: str, path_pattern: str, auto_save: bool = True, **kwargs):
    """Generates a ProjectModel object.

    By default, the generated ProjectModel is saved straight after creation.
    In some cases, it can be useful to get the floating (not recorded on the database)
    object in order to perform further operation, and save after that.
    That can be achieved by setting `auto_save` to False.

    Args:
      name: str: Name of the new model.
      path_pattern: str: Path pattern of the new model.
      auto_save: bool: If True, the returned object is saved. Otherwise it is floating. (Default value = True)
      **kwargs: Any non-mandatory valid attribute of ProjectModel can be passed.

    Raises:
        ValueError: Failed validation, if auto_save is True.
        TypeError: Failed validation, if auto_save is True.

    Returns:
        ProjectModel: Generated ProjectModel.
    """
    model = cls()
    model.name = name
    model.path_pattern = path_pattern

    # Add optional attributes
    model._add_dynamic_attributes(**kwargs)

    # Generate plural if not specified
    if not model.plural:
        model.plural = name + "s"

    if not model.folder_name:
        model.folder_name = string_cleaner(name, sep="_")

    if not model.code:
        model.code = string_cleaner(name, sep="_")

    if auto_save:
        model.save()

    return model

get(slug=None, uid=None) classmethod

Get a specific ProjectModel or all ProjectModels.

It is possible to get a specific ProjectModel from its uid or its slug. When providing one, the other can be left to None. If none of these two parameters are filled, The getter becomes a global getter and returns a collection.

Parameters:

Name Type Description Default
slug Optional[str]

Optional[str]: Slug of a ProjectModel. If specified, uid can be left blank. (Default value = None)

None
uid Optional[str]

Optional[str]: Uid of a ProjectModel. If specified, slug can be left blank. (Default value = None)

None

Raises:

Type Description
LookupError

No matching ProjectModel found.

Returns:

Type Description
Union[ProjectModel, List[ProjectModel], None]
  • list: Collection of ProjectModels, if no uid or slug specified.
Union[ProjectModel, List[ProjectModel], None]
  • ProjectModel: Single ProjectModel if a uid or a slug has been specified.
Source code in client/bip/link/project.py
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
@classmethod
def get(
    cls, slug: Optional[str] = None, uid: Optional[str] = None
) -> Union[ProjectModel, List[ProjectModel], None]:
    """Get a specific ProjectModel or all ProjectModels.

    It is possible to get a specific ProjectModel from its `uid` or its `slug`.
    When providing one, the other can be left to None. If none of these two parameters are filled,
    The getter becomes a global getter and returns a collection.

    Args:
        slug: Optional[str]: Slug of a ProjectModel. If specified, `uid` can be left blank. (Default value = None)
        uid: Optional[str]: Uid of a ProjectModel. If specified, `slug` can be left blank. (Default value = None)

    Raises:
        LookupError: No matching ProjectModel found.

    Returns:
        - list: Collection of ProjectModels, if no uid or slug specified.
        - ProjectModel: Single ProjectModel if a uid or a slug has been specified.
    """
    if uid or slug:
        result = sink.project.get_model(slug, uid)
        if not result:
            return
        return cls.from_dict(result)
    else:
        models = sink.project.get_models()
        return [cls.from_dict(t) for t in models]

get_projects()

Convenient class implementation of: bip.link.project.get_projects.

Warning

The signature of ProjectModel.get_projects() and bip.link.project.get_projects() are different since ProjectModel.get_projects() passes itself to the function as model=self.

Source code in client/bip/link/project.py
898
899
900
901
902
903
904
905
def get_projects(self) -> List[Project]:
    """Convenient class implementation of: `bip.link.project.get_projects`.

    !!! warning
        The signature of `ProjectModel.get_projects()` and `bip.link.project.get_projects()`
        are different since `ProjectModel.get_projects()` passes itself to the function as `model=self`.
    """
    return get_projects(model=self)

save()

Saves the ProjectModel to the database.

If the ProjectModel is floating, saving makes it persistent.

Attributes changes are not applied to the database at modification. Saving the ProjectModel does.

Raises:

Type Description
ValueError

Failed validation.

TypeError

Failed validation.

Source code in client/bip/link/project.py
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
def save(self):
    """Saves the ProjectModel to the database.

    If the ProjectModel is floating, saving makes it persistent.

    Attributes changes are not applied to the database at modification. Saving the ProjectModel does.

    Raises:
        ValueError: Failed validation.
        TypeError: Failed validation.
    """
    if not self._is_modified and self.uid:
        return

    if not self.uid:
        self._generate_uid()

    self._default()
    self._validate()

    sink.project.save_model(self.to_dict())

    self._sink()

    return self

get(slug=None, uid=None, model=None, open_only=False)

Convenient shortcut to Project.get for getting a specific Project or all Projects.

Source code in client/bip/link/project.py
1070
1071
1072
1073
1074
1075
1076
1077
def get(
    slug: Optional[str] = None,
    uid: Optional[str] = None,
    model: Optional[ProjectModel] = None,
    open_only: bool = False,
) -> Union[Project, List[Project]]:
    """Convenient shortcut to `Project.get` for getting a specific Project or all Projects."""
    return Project.get(slug=slug, uid=uid, model=model, open_only=open_only)

get_default_project_model()

Get the default ProjectModel of the Bip server, if any.

Returns:

Type Description
Union[None, ProjectModel]

Union[None, ProjectModel]: ProjectModel if a default is set, None otherwise.

Source code in client/bip/link/project.py
1153
1154
1155
1156
1157
1158
1159
1160
def get_default_project_model() -> Union[None, ProjectModel]:
    """Get the default ProjectModel of the Bip server, if any.

    Returns:
        Union[None, ProjectModel]: ProjectModel if a default is set, None otherwise."""
    model = sink.project.get_default_project_model()
    if model:
        return ProjectModel.from_dict(model)

get_folder_names()

Get all Projects folder names.

Utility function for path building.

Returns:

Name Type Description
dict Dict[str, str]

Pair or uid and folder names.

Source code in client/bip/link/project.py
1163
1164
1165
1166
1167
1168
1169
1170
1171
def get_folder_names() -> Dict[str, str]:
    """Get all Projects folder names.

    Utility function for path building.

    Returns:
        dict: Pair or uid and folder names.
    """
    return sink.project.get_folder_names()

get_model(slug=None, uid=None)

Convenient shortcut to ProjectModel.get for specific ProjectModel.

Raises:

Type Description
ValueError

No slug and no uid provided.

Source code in client/bip/link/project.py
1129
1130
1131
1132
1133
1134
1135
1136
1137
def get_model(slug: Optional[str] = None, uid: Optional[str] = None) -> ProjectModel:
    """Convenient shortcut to `ProjectModel.get` for specific ProjectModel.

    Raises:
        ValueError: No slug and no uid provided.
    """
    if not uid and not slug:
        raise ValueError("A uid or a slug must be provided.")
    return ProjectModel.get(slug=slug, uid=uid)

get_models()

Convenient shortcut to ProjectModel.get for all ProjectModel.

Source code in client/bip/link/project.py
1140
1141
1142
def get_models() -> List[ProjectModel]:
    """Convenient shortcut to `ProjectModel.get` for all ProjectModel."""
    return ProjectModel.get()

get_project(slug=None, uid=None, model=None)

Convenient shortcut to Project.get for getting a specific Project.

Raises:

Type Description
ValueError

No slug and no uid provided.

Source code in client/bip/link/project.py
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
def get_project(
    slug: Optional[str] = None,
    uid: Optional[str] = None,
    model: Optional[Union[str, ProjectModel]] = None,
) -> Project:
    """Convenient shortcut to `Project.get` for getting a specific Project.

    Raises:
        ValueError: No slug and no uid provided.
    """
    if not uid and not slug:
        raise ValueError("A uid or a slug must be provided.")
    return Project.get(slug=slug, uid=uid, model=model)

get_projects(model=None, open_only=False)

Convenient shortcut to Project.get for getting all Projects.

Source code in client/bip/link/project.py
1095
1096
1097
1098
1099
def get_projects(
    model: Optional[Union[str, ProjectModel]] = None, open_only: bool = False
) -> List[Project]:
    """Convenient shortcut to `Project.get` for getting all Projects."""
    return Project.get(model=model, open_only=open_only)

new(name, meta_model, slug=None, model=None, groups=(), auto_save=True, **kwargs)

Convenient shortcut to Project.generate.

Source code in client/bip/link/project.py
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
def new(
    name: str,
    meta_model: MetaModel,
    slug: Optional[str] = None,
    model: Optional[ProjectModel] = None,
    groups: Union[List, Tuple] = (),
    auto_save: bool = True,
    **kwargs,
) -> Project:
    """Convenient shortcut to `Project.generate`."""
    return Project.generate(name, meta_model, slug, model, groups, auto_save, **kwargs)

new_model(name, path_pattern, auto_save=True, **kwargs)

Convenient shortcut to ProjectModel.generate.

Source code in client/bip/link/project.py
1145
1146
1147
1148
1149
def new_model(
    name: str, path_pattern: str, auto_save: bool = True, **kwargs
) -> ProjectModel:
    """Convenient shortcut to `ProjectModel.generate`."""
    return ProjectModel.generate(name, path_pattern, auto_save, **kwargs)

new_project(name, meta_model, slug=None, model=None, groups=(), auto_save=True, **kwargs)

Convenient shortcut to Project.generate.

Source code in client/bip/link/project.py
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
def new_project(
    name: str,
    meta_model: MetaModel,
    slug: Optional[str] = None,
    model: Optional[ProjectModel] = None,
    groups: Union[List, Tuple] = (),
    auto_save: bool = True,
    **kwargs,
) -> Project:
    """Convenient shortcut to `Project.generate`."""
    return Project.generate(name, meta_model, slug, model, groups, auto_save, **kwargs)