Module coscine.project

This file defines the project object for the representation of Coscine projects. It provides a simple interface to interact with Coscine projects from python.

Expand source code
###############################################################################
# Coscine Python SDK
# Copyright (c) 2018-2022 RWTH Aachen University
# Licensed under the terms of the MIT License
# #############################################################################
# Coscine, short for Collaborative Scientific Integration Environment is
# a platform for research data management (RDM).
# For more information on Coscine visit https://www.coscine.de/.
#
# Please note that this python module is open source software primarily
# developed and maintained by the scientific community. It is not
# an official service that RWTH Aachen provides support for.
###############################################################################

###############################################################################
# File description
###############################################################################

"""
This file defines the project object for the representation of
Coscine projects. It provides a simple interface to interact with Coscine
projects from python.
"""

###############################################################################
# Dependencies
###############################################################################

from __future__ import annotations
from typing import TYPE_CHECKING, List
if TYPE_CHECKING:
        from .client import Client
from .exceptions import *
from .resource import Resource, ResourceForm
from .form import InputForm
from .defaults import TIMEFORMAT
from prettytable.prettytable import PrettyTable
from datetime import datetime
from urllib.parse import urljoin, urlparse
import json
import os

###############################################################################
# Class definition
###############################################################################

class ProjectForm(InputForm):
        """
        """

        parent: Project

###############################################################################

        def __init__(self, client: Client, parent: Project = None) -> None:
                self._items = client.vocabularies.builtin("project")
                self.parent = parent
                super().__init__(client)
                vocabularies = {
                        "disciplines": client.vocabularies.disciplines(True),
                        "organizations": client.vocabularies.organizations(True),
                        "visibility": client.vocabularies.visibility(True)
                }
                for item in self._items:
                        if item.vocabulary:
                                self._vocabularies[item.path] = vocabularies[item.path]

###############################################################################

        def _parse_organizations(self, data):
                organizations = []
                for value in data:
                        organization = {
                                #"displayName": urljoin(value["displayName"], urlparse(value["displayName"]).path),
                                "url": urljoin(value["url"], urlparse(value["url"]).path)
                        }
                        organizations.append(organization)
                        # organization vocabualry only contains 1st 100 entries
                        # can only filter, not get full
                return organizations

###############################################################################

        def parse(self, data: dict) -> None:
                IGNORE = ["id", "slug", "parentId"]
                if data is None:
                        return
                for path, value in data.items():
                        if path in IGNORE: continue
                        if path == "organizations":
                                value = self._parse_organizations(value)
                        key = self.name_of(path)
                        self.set_value(key, value, True)

###############################################################################

        def generate(self) -> dict:
                """
                """

                metadata = {}
                missing = []

                for key, values in self.items(True):
                        if not values:
                                if self.is_required(key):
                                        missing.append(key)
                                continue

                        properties = self.properties(key)
                        path = properties.path
                        metadata[path] = values if properties.maxCount > 1 else values[0]

                if missing:
                        raise ValueError(missing)

                if self.parent:
                        metadata["ParentId"] = self.parent.id
                
                return metadata

###############################################################################
# Class definition
###############################################################################

class Project:
        """
        Python representation of a Coscine Project
        """

        client: Client
        data: dict
        parent: Project

        id: str
        name: str
        displayName: str
        description: str
        principleInvestigators: str
        startDate: datetime
        endDate: datetime
        disciplines: List[str]
        organizations: List[str]
        visibility: str

        ###############################################################################

        def __init__(self, client: Client, data: dict,
                                        parent: Project = None) -> None:
                """
                Initializes a Coscine project object.

                Parameters
                ----------
                client : Client
                        Coscine client handle
                data : dict
                        Project data received from Coscine.
                parent : Project
                        Optional parent project.
                """

                self.client = client
                self.data = data
                self.parent = parent

###############################################################################

        @property
        def id(self) -> str: return self.data["id"]

        @property
        def name(self) -> str: return self.data["projectName"]

        @property
        def displayName(self) -> str: return self.data["displayName"]

        @property
        def description(self) -> str: return self.data["description"]

        @property
        def principleInvestigators(self) -> str:
                return self.data["principleInvestigators"]

        @property
        def startDate(self) -> datetime:
                return datetime.strptime(self.data["startDate"], TIMEFORMAT)

        @property
        def endDate(self) -> datetime:
                return datetime.strptime(self.data["endDate"], TIMEFORMAT)

        @property
        def disciplines(self) -> List[str]:
                lang = {
                        "en": "displayNameEn",
                        "de": "displayNameDe"
                }[self.client.language]
                return [k[lang] for k in self.data["disciplines"]]
        
        @property
        def organizations(self) -> List[str]:
                return[k["displayName"] for k in self.data["organizations"]]
        
        @property
        def visibility(self) -> str: return self.data["visibility"]["displayName"]

###############################################################################

        def __str__(self) -> str:
                table = PrettyTable(("Property", "Value"))
                rows = [
                        ("ID", self.id),
                        ("Name", self.name),
                        ("Display Name", self.displayName),
                        ("Principle Investigators", self.principleInvestigators),
                        ("Disciplines", "\n".join(self.disciplines)),
                        ("Organizations", "\n".join(self.organizations)),
                        ("Start Date", self.startDate),
                        ("End Date", self.endDate),
                        ("Visibility", self.visibility)
                ]
                table.max_width["Value"] = 50
                table.add_rows(rows)
                return table.get_string(title = "Project [%s]" % self.displayName)

###############################################################################

        def subprojects(self, **kwargs) -> List[Project]:
                """
                Retrieves a list of subprojects of the current project matching a set
                of specified filters

                Parameters
                ----------
                kwargs
                        key-value filters for subprojects (e.g. 'Name' = 'My Project').

                Returns
                -------
                list of Projects
                """

                uri = self.client.uri("Project", "SubProject", self.id)
                projects = self.client.get(uri).json()
                filter = []
                for data in projects:
                        match = True
                        for key, value in kwargs.items():
                                if data[key] != value:
                                        match = False
                                        break
                        if match:
                                filter.append(Project(self.client, data, self))
                return filter

###############################################################################

        def delete(self) -> None:
                """
                Deletes the project on the Coscine servers.
                """

                uri = self.client.uri("Project", "Project", self.id)
                self.client.delete(uri)

###############################################################################

        def resources(self, **kwargs) -> List[Resource]:
                """
                Retrieves a list of Resources of the current project matching a set
                of specified filters.

                Parameters
                ----------
                kwargs
                        key-value filters for resources (e.g. 'Name' = 'My Resource').
                
                Returns
                -------
                list[Resource]
                        list of resources matching the supplied filter.
                """

                uri = self.client.uri("Project", "Project", self.id, "resources")
                resources = []
                for it in self.client.get(uri).json():
                        for key, value in kwargs.items():
                                if it[key] != value:
                                        break
                        else:
                                resources.append(Resource(self, it))
                return resources

###############################################################################

        def resource(self, displayName: str = None, **kwargs) -> Resource:
                """
                Retrieves a certain resource of the current project matching a set
                of specified filters or identified by its displayName.

                Parameters
                ----------
                displayName : str
                        The display name of the resource.
                kwargs
                        key-value filters for resources (e.g. 'Name' = 'My Resource').
                
                Returns
                --------
                Resource or None
                """
                
                if displayName:
                        kwargs["displayName"] = displayName
                elif not kwargs:
                        raise ValueError("")

                resources = self.resources(**kwargs)
                if len(resources) == 1:
                        return resources[0]
                elif len(resources) == 0:
                        return None
                else:
                        raise ValueError("Found more than 1 resource matching "\
                                                                                "the specified criteria!")

###############################################################################

        def download(self, path: str = "./", metadata: bool = False) -> None:
                """
                Downloads the project to the location referenced by 'path'.

                Parameters
                ----------
                path : str
                        Download location on the harddrive
                        Default: current directory './'
                metadata : bool, default: False
                        If enabled, project metadata is downloaded and put in
                        a hidden file '.metadata.json'.
                """

                path = os.path.join(path, self.displayName)
                if not os.path.isdir(path):
                        os.mkdir(path)
                for resource in self.resources():
                        resource.download(path=path, metadata=metadata)
                if metadata:
                        data = json.dumps(self.data, indent=4)
                        fd = open(os.path.join(path, ".metadata.json"), "w")
                        fd.write(data)
                        fd.close()

###############################################################################

        def members(self) -> List[ProjectMember]:
                """
                Retrieves a list of all members of the current project

                Returns
                --------
                list[ProjectMember]
                        List of project members as ProjectMember objects.
                """

                uri = self.client.uri("Project", "ProjectRole", self.id)
                data = self.client.get(uri).json()
                members = [ProjectMember(self, m) for m in data]
                return members

###############################################################################

        def invite(self, email: str, role: str = "Member") -> None:
                """
                Invites a person to a project via their email address

                Parameters
                ----------
                email : str
                        The email address to send the invite to
                role : str, "Member" or "Owner", default: "Member"
                        The role for the new project member
                """

                if role not in ProjectMember.ROLES:
                        raise ValueError("Invalid role '%s'." % role)

                uri = self.client.uri("Project", "Project", "invitation")
                data = {
                        "projectId": self.data["id"],
                        "role": ProjectMember.ROLES[role],
                        "email": email
                }

                try:
                        self.client.log("Inviting [%s] as [%s] to project [%s]." % 
                                                                                                (email, role, self.id))
                        self.client.post(uri, data = data)
                except ServerError:
                        self.client.log("User [%s] has invite pending." % email)

###############################################################################

        def add_member(self, member: ProjectMember, role: str = "Member"):
                """
                Adds a project member of another project to the current project.

                Parameters
                ----------
                member : ProjectMember
                        Member of another Coscine project
                role : str, "Member" or "Owner", default: "Member"
                """

                if role not in ProjectMember.ROLES:
                        raise ValueError("Invalid role!")

                data = member.data
                data["projectId"] = self.id
                data["role"]["displayName"] = role
                data["role"]["id"] = ProjectMember.ROLES[role]
                uri = self.client.uri("Project", "ProjectRole")
                self.client.post(uri, data = data)

###############################################################################

        def form(self) -> ProjectForm:
                """
                """

                form = ProjectForm(self.client)
                form.parse(self.data)
                return form

###############################################################################

        def update(self, form: ProjectForm) -> dict:
                """
                Updates a project using the given ProjectForm

                Parameters
                ----------
                form : ProjectForm
                        ProjectForm containing updated data.
                """

                if type(form) is ProjectForm:
                        form = form.generate()
                uri = self.client.uri("Project", "Project", self.id)
                response = self.client.post(uri, data = form)
                if response.ok: self.data = response.json()
                return response

###############################################################################

        def create_resource(self, form: ResourceForm) -> Resource:
                """
                Creates a resource within the current project using the supplied
                resource form.

                Parameters
                ----------
                resourceForm : ResourceForm
                        Form to generate the resource with.
                metadataPreset : MetadataPresetForm
                        optional application profile configuration.
                """
                if type(form) is ResourceForm:
                        form = form.generate()
                uri = self.client.uri("Resources", "Resource", "Project", self.id)
                return Resource(self, self.client.post(uri, data = form).json())

###############################################################################
# Class definition
###############################################################################

class ProjectMember:

        """
        Initializes a project member for a given project.

        Parameters
        ----------
        project : Project
                Coscine python SDK project handle.
        data: dict
                User data as dict, retrieved via 
                client.uri("Project", "ProjectRole", self.id).
        """

        ROLES = {
                "Owner": "be294c5e-4e42-49b3-bec4-4b15f49df9a5",
                "Member": "508b6d4e-c6ac-4aa5-8a8d-caa31dd39527"
        }

        name: str
        email: str
        id: str
        role: str
        data: dict
        client: Client
        project: Project

###############################################################################

        def __init__(self, project: Project, data: dict) -> None:
                """
                """

                self.project = project
                self.client = self.project.client
                self.data = data
                self.name = data["user"]["displayName"]
                self.email = data["user"]["emailAddress"]
                self.id = data["user"]["id"]
                self.role = data["role"]["displayName"]

###############################################################################

        def set_role(self, role: str) -> None:

                """
                Sets the role of a project member

                Parameters
                ----------
                role : str
                        The new role of the member ('Owner' or 'Member').
                """

                ROLES = {
                        "Owner": "be294c5e-4e42-49b3-bec4-4b15f49df9a5",
                        "Member": "508b6d4e-c6ac-4aa5-8a8d-caa31dd39527"
                }

                if role not in ROLES:
                        raise ValueError("Invalid role '%s'." % role)

                uri = self.client.uri("Project", "ProjectRole")
                self.data["role"]["id"] = ROLES[role]
                self.data["role"]["displayName"] = role
                self.client.post(uri, data = self.data)

###############################################################################

        def remove(self) -> None:
                """
                Removes a project member from their associated project.
                """

                uri = self.client.uri("Project", "ProjectRole", "project", \
                        self.project.id, "user", self.id, "role", self.data["role"]["id"])
                self.client.delete(uri)

###############################################################################

Classes

class Project (client: Client, data: dict, parent: Project = None)

Python representation of a Coscine Project

Initializes a Coscine project object.

Parameters

client : Client
Coscine client handle
data : dict
Project data received from Coscine.
parent : Project
Optional parent project.
Expand source code
class Project:
        """
        Python representation of a Coscine Project
        """

        client: Client
        data: dict
        parent: Project

        id: str
        name: str
        displayName: str
        description: str
        principleInvestigators: str
        startDate: datetime
        endDate: datetime
        disciplines: List[str]
        organizations: List[str]
        visibility: str

        ###############################################################################

        def __init__(self, client: Client, data: dict,
                                        parent: Project = None) -> None:
                """
                Initializes a Coscine project object.

                Parameters
                ----------
                client : Client
                        Coscine client handle
                data : dict
                        Project data received from Coscine.
                parent : Project
                        Optional parent project.
                """

                self.client = client
                self.data = data
                self.parent = parent

###############################################################################

        @property
        def id(self) -> str: return self.data["id"]

        @property
        def name(self) -> str: return self.data["projectName"]

        @property
        def displayName(self) -> str: return self.data["displayName"]

        @property
        def description(self) -> str: return self.data["description"]

        @property
        def principleInvestigators(self) -> str:
                return self.data["principleInvestigators"]

        @property
        def startDate(self) -> datetime:
                return datetime.strptime(self.data["startDate"], TIMEFORMAT)

        @property
        def endDate(self) -> datetime:
                return datetime.strptime(self.data["endDate"], TIMEFORMAT)

        @property
        def disciplines(self) -> List[str]:
                lang = {
                        "en": "displayNameEn",
                        "de": "displayNameDe"
                }[self.client.language]
                return [k[lang] for k in self.data["disciplines"]]
        
        @property
        def organizations(self) -> List[str]:
                return[k["displayName"] for k in self.data["organizations"]]
        
        @property
        def visibility(self) -> str: return self.data["visibility"]["displayName"]

###############################################################################

        def __str__(self) -> str:
                table = PrettyTable(("Property", "Value"))
                rows = [
                        ("ID", self.id),
                        ("Name", self.name),
                        ("Display Name", self.displayName),
                        ("Principle Investigators", self.principleInvestigators),
                        ("Disciplines", "\n".join(self.disciplines)),
                        ("Organizations", "\n".join(self.organizations)),
                        ("Start Date", self.startDate),
                        ("End Date", self.endDate),
                        ("Visibility", self.visibility)
                ]
                table.max_width["Value"] = 50
                table.add_rows(rows)
                return table.get_string(title = "Project [%s]" % self.displayName)

###############################################################################

        def subprojects(self, **kwargs) -> List[Project]:
                """
                Retrieves a list of subprojects of the current project matching a set
                of specified filters

                Parameters
                ----------
                kwargs
                        key-value filters for subprojects (e.g. 'Name' = 'My Project').

                Returns
                -------
                list of Projects
                """

                uri = self.client.uri("Project", "SubProject", self.id)
                projects = self.client.get(uri).json()
                filter = []
                for data in projects:
                        match = True
                        for key, value in kwargs.items():
                                if data[key] != value:
                                        match = False
                                        break
                        if match:
                                filter.append(Project(self.client, data, self))
                return filter

###############################################################################

        def delete(self) -> None:
                """
                Deletes the project on the Coscine servers.
                """

                uri = self.client.uri("Project", "Project", self.id)
                self.client.delete(uri)

###############################################################################

        def resources(self, **kwargs) -> List[Resource]:
                """
                Retrieves a list of Resources of the current project matching a set
                of specified filters.

                Parameters
                ----------
                kwargs
                        key-value filters for resources (e.g. 'Name' = 'My Resource').
                
                Returns
                -------
                list[Resource]
                        list of resources matching the supplied filter.
                """

                uri = self.client.uri("Project", "Project", self.id, "resources")
                resources = []
                for it in self.client.get(uri).json():
                        for key, value in kwargs.items():
                                if it[key] != value:
                                        break
                        else:
                                resources.append(Resource(self, it))
                return resources

###############################################################################

        def resource(self, displayName: str = None, **kwargs) -> Resource:
                """
                Retrieves a certain resource of the current project matching a set
                of specified filters or identified by its displayName.

                Parameters
                ----------
                displayName : str
                        The display name of the resource.
                kwargs
                        key-value filters for resources (e.g. 'Name' = 'My Resource').
                
                Returns
                --------
                Resource or None
                """
                
                if displayName:
                        kwargs["displayName"] = displayName
                elif not kwargs:
                        raise ValueError("")

                resources = self.resources(**kwargs)
                if len(resources) == 1:
                        return resources[0]
                elif len(resources) == 0:
                        return None
                else:
                        raise ValueError("Found more than 1 resource matching "\
                                                                                "the specified criteria!")

###############################################################################

        def download(self, path: str = "./", metadata: bool = False) -> None:
                """
                Downloads the project to the location referenced by 'path'.

                Parameters
                ----------
                path : str
                        Download location on the harddrive
                        Default: current directory './'
                metadata : bool, default: False
                        If enabled, project metadata is downloaded and put in
                        a hidden file '.metadata.json'.
                """

                path = os.path.join(path, self.displayName)
                if not os.path.isdir(path):
                        os.mkdir(path)
                for resource in self.resources():
                        resource.download(path=path, metadata=metadata)
                if metadata:
                        data = json.dumps(self.data, indent=4)
                        fd = open(os.path.join(path, ".metadata.json"), "w")
                        fd.write(data)
                        fd.close()

###############################################################################

        def members(self) -> List[ProjectMember]:
                """
                Retrieves a list of all members of the current project

                Returns
                --------
                list[ProjectMember]
                        List of project members as ProjectMember objects.
                """

                uri = self.client.uri("Project", "ProjectRole", self.id)
                data = self.client.get(uri).json()
                members = [ProjectMember(self, m) for m in data]
                return members

###############################################################################

        def invite(self, email: str, role: str = "Member") -> None:
                """
                Invites a person to a project via their email address

                Parameters
                ----------
                email : str
                        The email address to send the invite to
                role : str, "Member" or "Owner", default: "Member"
                        The role for the new project member
                """

                if role not in ProjectMember.ROLES:
                        raise ValueError("Invalid role '%s'." % role)

                uri = self.client.uri("Project", "Project", "invitation")
                data = {
                        "projectId": self.data["id"],
                        "role": ProjectMember.ROLES[role],
                        "email": email
                }

                try:
                        self.client.log("Inviting [%s] as [%s] to project [%s]." % 
                                                                                                (email, role, self.id))
                        self.client.post(uri, data = data)
                except ServerError:
                        self.client.log("User [%s] has invite pending." % email)

###############################################################################

        def add_member(self, member: ProjectMember, role: str = "Member"):
                """
                Adds a project member of another project to the current project.

                Parameters
                ----------
                member : ProjectMember
                        Member of another Coscine project
                role : str, "Member" or "Owner", default: "Member"
                """

                if role not in ProjectMember.ROLES:
                        raise ValueError("Invalid role!")

                data = member.data
                data["projectId"] = self.id
                data["role"]["displayName"] = role
                data["role"]["id"] = ProjectMember.ROLES[role]
                uri = self.client.uri("Project", "ProjectRole")
                self.client.post(uri, data = data)

###############################################################################

        def form(self) -> ProjectForm:
                """
                """

                form = ProjectForm(self.client)
                form.parse(self.data)
                return form

###############################################################################

        def update(self, form: ProjectForm) -> dict:
                """
                Updates a project using the given ProjectForm

                Parameters
                ----------
                form : ProjectForm
                        ProjectForm containing updated data.
                """

                if type(form) is ProjectForm:
                        form = form.generate()
                uri = self.client.uri("Project", "Project", self.id)
                response = self.client.post(uri, data = form)
                if response.ok: self.data = response.json()
                return response

###############################################################################

        def create_resource(self, form: ResourceForm) -> Resource:
                """
                Creates a resource within the current project using the supplied
                resource form.

                Parameters
                ----------
                resourceForm : ResourceForm
                        Form to generate the resource with.
                metadataPreset : MetadataPresetForm
                        optional application profile configuration.
                """
                if type(form) is ResourceForm:
                        form = form.generate()
                uri = self.client.uri("Resources", "Resource", "Project", self.id)
                return Resource(self, self.client.post(uri, data = form).json())

Class variables

var client : Client
var data : dict
var parentProject

Instance variables

var description : str
Expand source code
@property
def description(self) -> str: return self.data["description"]
var disciplines : List[str]
Expand source code
@property
def disciplines(self) -> List[str]:
        lang = {
                "en": "displayNameEn",
                "de": "displayNameDe"
        }[self.client.language]
        return [k[lang] for k in self.data["disciplines"]]
var displayName : str
Expand source code
@property
def displayName(self) -> str: return self.data["displayName"]
var endDate : datetime.datetime
Expand source code
@property
def endDate(self) -> datetime:
        return datetime.strptime(self.data["endDate"], TIMEFORMAT)
var id : str
Expand source code
@property
def id(self) -> str: return self.data["id"]
var name : str
Expand source code
@property
def name(self) -> str: return self.data["projectName"]
var organizations : List[str]
Expand source code
@property
def organizations(self) -> List[str]:
        return[k["displayName"] for k in self.data["organizations"]]
var principleInvestigators : str
Expand source code
@property
def principleInvestigators(self) -> str:
        return self.data["principleInvestigators"]
var startDate : datetime.datetime
Expand source code
@property
def startDate(self) -> datetime:
        return datetime.strptime(self.data["startDate"], TIMEFORMAT)
var visibility : str
Expand source code
@property
def visibility(self) -> str: return self.data["visibility"]["displayName"]

Methods

def add_member(self, member: ProjectMember, role: str = 'Member')

Adds a project member of another project to the current project.

Parameters

member : ProjectMember
Member of another Coscine project
role : str, "Member" or "Owner", default: "Member"
 
Expand source code
def add_member(self, member: ProjectMember, role: str = "Member"):
        """
        Adds a project member of another project to the current project.

        Parameters
        ----------
        member : ProjectMember
                Member of another Coscine project
        role : str, "Member" or "Owner", default: "Member"
        """

        if role not in ProjectMember.ROLES:
                raise ValueError("Invalid role!")

        data = member.data
        data["projectId"] = self.id
        data["role"]["displayName"] = role
        data["role"]["id"] = ProjectMember.ROLES[role]
        uri = self.client.uri("Project", "ProjectRole")
        self.client.post(uri, data = data)
def create_resource(self, form: ResourceForm) ‑> Resource

Creates a resource within the current project using the supplied resource form.

Parameters

resourceForm : ResourceForm
Form to generate the resource with.
metadataPreset : MetadataPresetForm
optional application profile configuration.
Expand source code
def create_resource(self, form: ResourceForm) -> Resource:
        """
        Creates a resource within the current project using the supplied
        resource form.

        Parameters
        ----------
        resourceForm : ResourceForm
                Form to generate the resource with.
        metadataPreset : MetadataPresetForm
                optional application profile configuration.
        """
        if type(form) is ResourceForm:
                form = form.generate()
        uri = self.client.uri("Resources", "Resource", "Project", self.id)
        return Resource(self, self.client.post(uri, data = form).json())
def delete(self) ‑> None

Deletes the project on the Coscine servers.

Expand source code
def delete(self) -> None:
        """
        Deletes the project on the Coscine servers.
        """

        uri = self.client.uri("Project", "Project", self.id)
        self.client.delete(uri)
def download(self, path: str = './', metadata: bool = False) ‑> None

Downloads the project to the location referenced by 'path'.

Parameters

path : str
Download location on the harddrive Default: current directory './'
metadata : bool, default: False
If enabled, project metadata is downloaded and put in a hidden file '.metadata.json'.
Expand source code
def download(self, path: str = "./", metadata: bool = False) -> None:
        """
        Downloads the project to the location referenced by 'path'.

        Parameters
        ----------
        path : str
                Download location on the harddrive
                Default: current directory './'
        metadata : bool, default: False
                If enabled, project metadata is downloaded and put in
                a hidden file '.metadata.json'.
        """

        path = os.path.join(path, self.displayName)
        if not os.path.isdir(path):
                os.mkdir(path)
        for resource in self.resources():
                resource.download(path=path, metadata=metadata)
        if metadata:
                data = json.dumps(self.data, indent=4)
                fd = open(os.path.join(path, ".metadata.json"), "w")
                fd.write(data)
                fd.close()
def form(self) ‑> ProjectForm
Expand source code
def form(self) -> ProjectForm:
        """
        """

        form = ProjectForm(self.client)
        form.parse(self.data)
        return form
def invite(self, email: str, role: str = 'Member') ‑> None

Invites a person to a project via their email address

Parameters

email : str
The email address to send the invite to
role : str, "Member" or "Owner", default: "Member"
The role for the new project member
Expand source code
def invite(self, email: str, role: str = "Member") -> None:
        """
        Invites a person to a project via their email address

        Parameters
        ----------
        email : str
                The email address to send the invite to
        role : str, "Member" or "Owner", default: "Member"
                The role for the new project member
        """

        if role not in ProjectMember.ROLES:
                raise ValueError("Invalid role '%s'." % role)

        uri = self.client.uri("Project", "Project", "invitation")
        data = {
                "projectId": self.data["id"],
                "role": ProjectMember.ROLES[role],
                "email": email
        }

        try:
                self.client.log("Inviting [%s] as [%s] to project [%s]." % 
                                                                                        (email, role, self.id))
                self.client.post(uri, data = data)
        except ServerError:
                self.client.log("User [%s] has invite pending." % email)
def members(self) ‑> List[ProjectMember]

Retrieves a list of all members of the current project

Returns

list[ProjectMember]
List of project members as ProjectMember objects.
Expand source code
def members(self) -> List[ProjectMember]:
        """
        Retrieves a list of all members of the current project

        Returns
        --------
        list[ProjectMember]
                List of project members as ProjectMember objects.
        """

        uri = self.client.uri("Project", "ProjectRole", self.id)
        data = self.client.get(uri).json()
        members = [ProjectMember(self, m) for m in data]
        return members
def resource(self, displayName: str = None, **kwargs) ‑> Resource

Retrieves a certain resource of the current project matching a set of specified filters or identified by its displayName.

Parameters

displayName : str
The display name of the resource.
kwargs
key-value filters for resources (e.g. 'Name' = 'My Resource').

Returns

Resource or None
 
Expand source code
def resource(self, displayName: str = None, **kwargs) -> Resource:
        """
        Retrieves a certain resource of the current project matching a set
        of specified filters or identified by its displayName.

        Parameters
        ----------
        displayName : str
                The display name of the resource.
        kwargs
                key-value filters for resources (e.g. 'Name' = 'My Resource').
        
        Returns
        --------
        Resource or None
        """
        
        if displayName:
                kwargs["displayName"] = displayName
        elif not kwargs:
                raise ValueError("")

        resources = self.resources(**kwargs)
        if len(resources) == 1:
                return resources[0]
        elif len(resources) == 0:
                return None
        else:
                raise ValueError("Found more than 1 resource matching "\
                                                                        "the specified criteria!")
def resources(self, **kwargs) ‑> List[Resource]

Retrieves a list of Resources of the current project matching a set of specified filters.

Parameters

kwargs
key-value filters for resources (e.g. 'Name' = 'My Resource').

Returns

list[Resource]
list of resources matching the supplied filter.
Expand source code
def resources(self, **kwargs) -> List[Resource]:
        """
        Retrieves a list of Resources of the current project matching a set
        of specified filters.

        Parameters
        ----------
        kwargs
                key-value filters for resources (e.g. 'Name' = 'My Resource').
        
        Returns
        -------
        list[Resource]
                list of resources matching the supplied filter.
        """

        uri = self.client.uri("Project", "Project", self.id, "resources")
        resources = []
        for it in self.client.get(uri).json():
                for key, value in kwargs.items():
                        if it[key] != value:
                                break
                else:
                        resources.append(Resource(self, it))
        return resources
def subprojects(self, **kwargs) ‑> List[Project]

Retrieves a list of subprojects of the current project matching a set of specified filters

Parameters

kwargs
key-value filters for subprojects (e.g. 'Name' = 'My Project').

Returns

list of Projects
 
Expand source code
def subprojects(self, **kwargs) -> List[Project]:
        """
        Retrieves a list of subprojects of the current project matching a set
        of specified filters

        Parameters
        ----------
        kwargs
                key-value filters for subprojects (e.g. 'Name' = 'My Project').

        Returns
        -------
        list of Projects
        """

        uri = self.client.uri("Project", "SubProject", self.id)
        projects = self.client.get(uri).json()
        filter = []
        for data in projects:
                match = True
                for key, value in kwargs.items():
                        if data[key] != value:
                                match = False
                                break
                if match:
                        filter.append(Project(self.client, data, self))
        return filter
def update(self, form: ProjectForm) ‑> dict

Updates a project using the given ProjectForm

Parameters

form : ProjectForm
ProjectForm containing updated data.
Expand source code
def update(self, form: ProjectForm) -> dict:
        """
        Updates a project using the given ProjectForm

        Parameters
        ----------
        form : ProjectForm
                ProjectForm containing updated data.
        """

        if type(form) is ProjectForm:
                form = form.generate()
        uri = self.client.uri("Project", "Project", self.id)
        response = self.client.post(uri, data = form)
        if response.ok: self.data = response.json()
        return response
class ProjectForm (client: Client, parent: Project = None)
Expand source code
class ProjectForm(InputForm):
        """
        """

        parent: Project

###############################################################################

        def __init__(self, client: Client, parent: Project = None) -> None:
                self._items = client.vocabularies.builtin("project")
                self.parent = parent
                super().__init__(client)
                vocabularies = {
                        "disciplines": client.vocabularies.disciplines(True),
                        "organizations": client.vocabularies.organizations(True),
                        "visibility": client.vocabularies.visibility(True)
                }
                for item in self._items:
                        if item.vocabulary:
                                self._vocabularies[item.path] = vocabularies[item.path]

###############################################################################

        def _parse_organizations(self, data):
                organizations = []
                for value in data:
                        organization = {
                                #"displayName": urljoin(value["displayName"], urlparse(value["displayName"]).path),
                                "url": urljoin(value["url"], urlparse(value["url"]).path)
                        }
                        organizations.append(organization)
                        # organization vocabualry only contains 1st 100 entries
                        # can only filter, not get full
                return organizations

###############################################################################

        def parse(self, data: dict) -> None:
                IGNORE = ["id", "slug", "parentId"]
                if data is None:
                        return
                for path, value in data.items():
                        if path in IGNORE: continue
                        if path == "organizations":
                                value = self._parse_organizations(value)
                        key = self.name_of(path)
                        self.set_value(key, value, True)

###############################################################################

        def generate(self) -> dict:
                """
                """

                metadata = {}
                missing = []

                for key, values in self.items(True):
                        if not values:
                                if self.is_required(key):
                                        missing.append(key)
                                continue

                        properties = self.properties(key)
                        path = properties.path
                        metadata[path] = values if properties.maxCount > 1 else values[0]

                if missing:
                        raise ValueError(missing)

                if self.parent:
                        metadata["ParentId"] = self.parent.id
                
                return metadata

Ancestors

  • InputForm
  • collections.abc.MutableMapping
  • collections.abc.Mapping
  • collections.abc.Collection
  • collections.abc.Sized
  • collections.abc.Iterable
  • collections.abc.Container
  • typing.Generic

Class variables

var parentProject

Inherited members

class ProjectMember (project: Project, data: dict)

Initializes a project member for a given project.

Parameters

project : Project
Coscine python SDK project handle.
data : dict
User data as dict, retrieved via client.uri("Project", "ProjectRole", self.id).
Expand source code
class ProjectMember:

        """
        Initializes a project member for a given project.

        Parameters
        ----------
        project : Project
                Coscine python SDK project handle.
        data: dict
                User data as dict, retrieved via 
                client.uri("Project", "ProjectRole", self.id).
        """

        ROLES = {
                "Owner": "be294c5e-4e42-49b3-bec4-4b15f49df9a5",
                "Member": "508b6d4e-c6ac-4aa5-8a8d-caa31dd39527"
        }

        name: str
        email: str
        id: str
        role: str
        data: dict
        client: Client
        project: Project

###############################################################################

        def __init__(self, project: Project, data: dict) -> None:
                """
                """

                self.project = project
                self.client = self.project.client
                self.data = data
                self.name = data["user"]["displayName"]
                self.email = data["user"]["emailAddress"]
                self.id = data["user"]["id"]
                self.role = data["role"]["displayName"]

###############################################################################

        def set_role(self, role: str) -> None:

                """
                Sets the role of a project member

                Parameters
                ----------
                role : str
                        The new role of the member ('Owner' or 'Member').
                """

                ROLES = {
                        "Owner": "be294c5e-4e42-49b3-bec4-4b15f49df9a5",
                        "Member": "508b6d4e-c6ac-4aa5-8a8d-caa31dd39527"
                }

                if role not in ROLES:
                        raise ValueError("Invalid role '%s'." % role)

                uri = self.client.uri("Project", "ProjectRole")
                self.data["role"]["id"] = ROLES[role]
                self.data["role"]["displayName"] = role
                self.client.post(uri, data = self.data)

###############################################################################

        def remove(self) -> None:
                """
                Removes a project member from their associated project.
                """

                uri = self.client.uri("Project", "ProjectRole", "project", \
                        self.project.id, "user", self.id, "role", self.data["role"]["id"])
                self.client.delete(uri)

Class variables

var ROLES
var client : Client
var data : dict
var email : str
var id : str
var name : str
var projectProject
var role : str

Methods

def remove(self) ‑> None

Removes a project member from their associated project.

Expand source code
def remove(self) -> None:
        """
        Removes a project member from their associated project.
        """

        uri = self.client.uri("Project", "ProjectRole", "project", \
                self.project.id, "user", self.id, "role", self.data["role"]["id"])
        self.client.delete(uri)
def set_role(self, role: str) ‑> None

Sets the role of a project member

Parameters

role : str
The new role of the member ('Owner' or 'Member').
Expand source code
def set_role(self, role: str) -> None:

        """
        Sets the role of a project member

        Parameters
        ----------
        role : str
                The new role of the member ('Owner' or 'Member').
        """

        ROLES = {
                "Owner": "be294c5e-4e42-49b3-bec4-4b15f49df9a5",
                "Member": "508b6d4e-c6ac-4aa5-8a8d-caa31dd39527"
        }

        if role not in ROLES:
                raise ValueError("Invalid role '%s'." % role)

        uri = self.client.uri("Project", "ProjectRole")
        self.data["role"]["id"] = ROLES[role]
        self.data["role"]["displayName"] = role
        self.client.post(uri, data = self.data)