/
project.py
175 lines (145 loc) · 6.76 KB
/
project.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# -*- coding: utf-8 -*-
#
# Copyright 2017-2021 - Swiss Data Science Center (SDSC)
# A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
# Eidgenössische Technische Hochschule Zürich (ETHZ).
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Project class."""
from datetime import datetime
from typing import Dict, List
from urllib.parse import quote
from marshmallow import EXCLUDE
from renku.core import errors
from renku.core.metadata.database import persistent
from renku.core.models.calamus import DateTimeList, JsonLDSchema, Nested, StringList, fields, oa, prov, renku, schema
from renku.core.models.provenance.agent import Person, PersonSchema
from renku.core.models.provenance.annotation import Annotation, AnnotationSchema
from renku.core.utils.datetime8601 import fix_datetime, local_now, parse_date
from renku.core.utils.scm import normalize_to_ascii
class Project(persistent.Persistent):
"""Represent a project."""
def __init__(
self,
*,
agent_version: str = None,
annotations: List[Annotation] = None,
automated_update: bool = False,
creator: Person,
date_created: datetime = None,
description: str = None,
id: str = None,
immutable_template_files: List[str] = None,
name: str,
template_id: str = None,
template_metadata: str = "{}",
template_ref: str = None,
template_source: str = None,
template_version: str = None,
version: str = None,
):
from renku.core.management.migrate import SUPPORTED_PROJECT_VERSION
version = version or SUPPORTED_PROJECT_VERSION
date_created = parse_date(date_created) or local_now()
if not id:
namespace, name = Project.get_namespace_and_name(name=name, creator=creator)
id = Project.generate_id(namespace=namespace, name=name)
self.agent_version: str = agent_version
self.annotations: List[Annotation] = annotations or []
self.automated_update: bool = automated_update
self.creator: Person = creator
self.date_created: datetime = fix_datetime(date_created) or local_now()
self.description: str = description
self.id: str = id
self.immutable_template_files: List[str] = immutable_template_files
self.name: str = name
self.template_id: str = template_id
self.template_metadata: str = template_metadata
self.template_ref: str = template_ref
self.template_source: str = template_source
self.template_version: str = template_version
self.version: str = version
@classmethod
def from_client(
cls,
client,
name: str = None,
description: str = None,
custom_metadata: Dict = None,
creator: Person = None,
) -> "Project":
"""Create an instance from a LocalClient."""
namespace, name = cls.get_namespace_and_name(client=client, name=name, creator=creator)
creator = creator or Person.from_git(client.repo)
annotations = None
if custom_metadata:
annotations = [Annotation(id=Annotation.generate_id(), body=custom_metadata, source="renku")]
if not creator:
raise ValueError("Project Creator not set")
id = cls.generate_id(namespace=namespace, name=name)
return cls(creator=creator, id=id, name=name, description=description, annotations=annotations)
@staticmethod
def get_namespace_and_name(*, client=None, name: str = None, creator: Person = None):
"""Return Project's namespace and name from various objects."""
namespace = None
if client:
remote = client.remote
namespace = remote.get("owner")
name = remote.get("name") or name
if not creator:
creator = Person.from_git(client.repo)
if not namespace and creator:
namespace = creator.email.split("@")[0]
return namespace, name
@staticmethod
def generate_id(namespace: str, name: str):
"""Generate an id for Project."""
assert namespace, "Cannot generate Project id with no namespace"
assert name, "Cannot generate Project id with no name"
namespace = quote(namespace.strip("/"), safe="/")
slug = normalize_to_ascii(name)
return f"/projects/{namespace}/{slug}"
def update_metadata(self, custom_metadata=None, **kwargs):
"""Updates metadata."""
editable_attributes = ["creator", "description"]
for name, value in kwargs.items():
if name not in editable_attributes:
raise errors.ParameterError(f"Cannot edit field: '{name}'")
if value and value != getattr(self, name):
setattr(self, name, value)
if custom_metadata:
existing_metadata = [a for a in self.annotations if a.source != "renku"]
existing_metadata.append(Annotation(id=Annotation.generate_id(), body=custom_metadata, source="renku"))
self.annotations = existing_metadata
class ProjectSchema(JsonLDSchema):
"""Project Schema."""
class Meta:
"""Meta class."""
rdf_type = [schema.Project, prov.Location]
model = Project
unknown = EXCLUDE
agent_version = StringList(schema.agent, missing="pre-0.11.0")
annotations = Nested(oa.hasTarget, AnnotationSchema, reverse=True, many=True)
automated_update = fields.Boolean(renku.automatedTemplateUpdate, missing=False)
creator = Nested(schema.creator, PersonSchema, missing=None)
date_created = DateTimeList(schema.dateCreated, missing=None, format="iso", extra_formats=("%Y-%m-%d",))
description = fields.String(schema.description, missing=None)
id = fields.Id(missing=None)
immutable_template_files = fields.List(renku.immutableTemplateFiles, fields.String(), missing=[])
name = fields.String(schema.name, missing=None)
template_id = fields.String(renku.templateId, missing=None)
template_metadata = fields.String(renku.templateMetadata, missing=None)
template_ref = fields.String(renku.templateReference, missing=None)
template_source = fields.String(renku.templateSource, missing=None)
template_version = fields.String(renku.templateVersion, missing=None)
version = StringList(schema.schemaVersion, missing="1")