Skip to content

Commit a9af501

Browse files
authored
Merge branch 'master' into 2405-pyproject.toml
2 parents 56a6bd2 + 5943f5f commit a9af501

File tree

16 files changed

+362
-17
lines changed

16 files changed

+362
-17
lines changed

renku/cli/dataset.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ def list_dataset(format, columns):
474474
type=click.Path(exists=True, dir_okay=False),
475475
help="Custom metadata to be associated with the dataset.",
476476
)
477-
@click.option("-k", "--keyword", default=None, multiple=True, type=click.STRING, help="List of keywords or tags.")
477+
@click.option("-k", "--keyword", default=None, multiple=True, type=click.STRING, help="List of keywords.")
478478
def create(name, title, description, creators, metadata, keyword):
479479
"""Create an empty dataset in the current repo."""
480480
from renku.core.commands.dataset import create_dataset

renku/cli/init.py

+3
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ def resolve_data_directory(data_dir, path):
248248
@click.argument("path", default=".", type=click.Path(writable=True, file_okay=False, resolve_path=True))
249249
@click.option("-n", "--name", callback=validate_name, help="Provide a custom project name.")
250250
@click.option("--description", help="Provide a description for the project.")
251+
@click.option("-k", "--keyword", default=None, multiple=True, type=click.STRING, help="List of keywords.")
251252
@click.option(
252253
"--data-dir",
253254
default=None,
@@ -292,6 +293,7 @@ def init(
292293
path,
293294
name,
294295
description,
296+
keyword,
295297
template_id,
296298
template_index,
297299
template_source,
@@ -327,6 +329,7 @@ def init(
327329
path=path,
328330
name=name,
329331
description=description,
332+
keywords=keyword,
330333
template_id=template_id,
331334
template_index=template_index,
332335
template_source=template_source,

renku/cli/project.py

+47-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,23 @@
1717
# limitations under the License.
1818
r"""Renku CLI commands for handling of projects.
1919
20+
Showing project metadata
21+
~~~~~~~~~~~~~~~~~~~~~~~~
22+
23+
You can see the metadata of the current project by using ``renku project show``:
24+
.. code-block:: console
25+
26+
$ renku project show
27+
Id: /projects/john.doe/flights-tutorial
28+
Name: flights-tutorial
29+
Description: Flight tutorial project
30+
Creator: John Doe <John [email protected]>
31+
Created: 2021-11-05T10:32:57+01:00
32+
Keywords: keyword1, keyword2
33+
Renku Version: 1.0.0
34+
Project Template: python-minimal (1.0.0)
35+
36+
2037
Editing projects
2138
~~~~~~~~~~~~~~~~
2239
@@ -55,6 +72,7 @@ def project():
5572

5673
@project.command()
5774
@click.option("-d", "--description", default=None, type=click.STRING, help="Project's description.")
75+
@click.option("-k", "--keyword", default=None, multiple=True, type=click.STRING, help="List of keywords.")
5876
@click.option(
5977
"-c",
6078
"--creator",
@@ -69,7 +87,7 @@ def project():
6987
type=click.Path(exists=True, dir_okay=False),
7088
help="Custom metadata to be associated with the project.",
7189
)
72-
def edit(description, creator, metadata):
90+
def edit(description, keyword, creator, metadata):
7391
"""Edit project metadata."""
7492
from renku.core.commands.project import edit_project_command
7593

@@ -81,7 +99,7 @@ def edit(description, creator, metadata):
8199
result = (
82100
edit_project_command()
83101
.build()
84-
.execute(description=description, creator=creator, custom_metadata=custom_metadata)
102+
.execute(description=description, creator=creator, keywords=keyword, custom_metadata=custom_metadata)
85103
)
86104

87105
updated, no_email_warning = result.output
@@ -92,3 +110,30 @@ def edit(description, creator, metadata):
92110
click.echo("Successfully updated: {}.".format(", ".join(updated.keys())))
93111
if no_email_warning:
94112
click.echo(ClickCallback.WARNING + f"No email or wrong format for: {no_email_warning}")
113+
114+
115+
def _print_project(project):
116+
"""Print project metadata."""
117+
click.echo(click.style("Id: ", bold=True, fg="magenta") + click.style(project.id, bold=True))
118+
click.echo(click.style("Name: ", bold=True, fg="magenta") + click.style(project.name, bold=True))
119+
click.echo(click.style("Description: ", bold=True, fg="magenta") + click.style(project.description, bold=True))
120+
click.echo(click.style("Creator: ", bold=True, fg="magenta") + click.style(project.creator_str, bold=True))
121+
click.echo(click.style("Created: ", bold=True, fg="magenta") + click.style(project.created_str, bold=True))
122+
click.echo(click.style("Keywords: ", bold=True, fg="magenta") + click.style(project.keywords_str, bold=True))
123+
click.echo(click.style("Renku Version: ", bold=True, fg="magenta") + click.style(project.agent, bold=True))
124+
click.echo(
125+
click.style("Project Template: ", bold=True, fg="magenta") + click.style(project.template_info, bold=True)
126+
)
127+
128+
if project.annotations:
129+
click.echo(click.style("Annotations: ", bold=True, fg="magenta") + click.style(project.annotations, bold=True))
130+
131+
132+
@project.command()
133+
def show():
134+
"""Show details for the project."""
135+
from renku.core.commands.project import show_project_command
136+
137+
project = show_project_command().build().execute().output
138+
139+
_print_project(project)

renku/core/commands/init.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ def _init(
237237
path,
238238
name,
239239
description,
240+
keywords,
240241
template_id,
241242
template_index,
242243
template_source,
@@ -351,6 +352,7 @@ def _init(
351352
force=force,
352353
data_dir=data_dir,
353354
description=description,
355+
keywords=keywords,
354356
)
355357
except FileExistsError as e:
356358
raise errors.InvalidFileOperation(e)
@@ -503,6 +505,7 @@ def create_from_template(
503505
user=None,
504506
commit_message=None,
505507
description=None,
508+
keywords=None,
506509
):
507510
"""Initialize a new project from a template."""
508511

@@ -521,7 +524,9 @@ def create_from_template(
521524
metadata["name"] = name
522525

523526
with client.commit(commit_message=commit_message, commit_only=commit_only, skip_dirty_checks=True):
524-
with client.with_metadata(name=name, description=description, custom_metadata=custom_metadata) as project:
527+
with client.with_metadata(
528+
name=name, description=description, custom_metadata=custom_metadata, keywords=keywords
529+
) as project:
525530
project.template_source = metadata["__template_source__"]
526531
project.template_ref = metadata["__template_ref__"]
527532
project.template_id = metadata["__template_id__"]
@@ -554,6 +559,7 @@ def _create_from_template_local(
554559
initial_branch=None,
555560
commit_message=None,
556561
description=None,
562+
keywords=None,
557563
):
558564
"""Initialize a new project from a template."""
559565

@@ -580,6 +586,7 @@ def _create_from_template_local(
580586
user=user,
581587
commit_message=commit_message,
582588
description=description,
589+
keywords=keywords,
583590
)
584591

585592

renku/core/commands/project.py

+23-3
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,34 @@
1717
# limitations under the License.
1818
"""Project management."""
1919

20+
from renku.core.commands.view_model.project import ProjectViewModel
2021
from renku.core.management.command_builder import inject
2122
from renku.core.management.command_builder.command import Command
23+
from renku.core.management.interface.client_dispatcher import IClientDispatcher
2224
from renku.core.management.interface.project_gateway import IProjectGateway
2325
from renku.core.management.repository import DATABASE_METADATA_PATH
2426
from renku.core.utils.metadata import construct_creator
2527

2628

2729
@inject.autoparams()
28-
def _edit_project(description, creator, custom_metadata, project_gateway: IProjectGateway):
30+
def _edit_project(description, creator, keywords, custom_metadata, project_gateway: IProjectGateway):
2931
"""Edit dataset metadata."""
30-
possible_updates = {"creator": creator, "description": description, "custom_metadata": custom_metadata}
32+
possible_updates = {
33+
"creator": creator,
34+
"description": description,
35+
"keywords": keywords,
36+
"custom_metadata": custom_metadata,
37+
}
3138

3239
creator, no_email_warnings = construct_creator(creator, ignore_email=True)
3340

3441
updated = {k: v for k, v in possible_updates.items() if v}
3542

3643
if updated:
3744
project = project_gateway.get_project()
38-
project.update_metadata(creator=creator, description=description, custom_metadata=custom_metadata)
45+
project.update_metadata(
46+
creator=creator, description=description, keywords=keywords, custom_metadata=custom_metadata
47+
)
3948
project_gateway.update_project(project)
4049

4150
return updated, no_email_warnings
@@ -45,3 +54,14 @@ def edit_project_command():
4554
"""Command for editing project metadata."""
4655
command = Command().command(_edit_project).lock_project().with_database(write=True)
4756
return command.require_migration().with_commit(commit_only=DATABASE_METADATA_PATH)
57+
58+
59+
@inject.autoparams()
60+
def _show_project(client_dispatcher: IClientDispatcher):
61+
"""Show project metadata."""
62+
return ProjectViewModel.from_project(client_dispatcher.current_client.project)
63+
64+
65+
def show_project_command():
66+
"""Command for showing project metadata."""
67+
return Command().command(_show_project).lock_project().with_database().require_migration()
+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright 2017-2021 - Swiss Data Science Center (SDSC)
4+
# A partnership between École Polytechnique Fédérale de Lausanne (EPFL) and
5+
# Eidgenössische Technische Hochschule Zürich (ETHZ).
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
"""Project view model."""
19+
20+
import json
21+
from datetime import datetime
22+
from typing import List, Optional
23+
24+
from renku.core.models.project import Project
25+
from renku.core.models.provenance.agent import Person
26+
27+
28+
class ProjectViewModel:
29+
"""A view model for a ``Project``."""
30+
31+
def __init__(
32+
self,
33+
id: str,
34+
name: str,
35+
creator: Person,
36+
created: datetime,
37+
description: str,
38+
agent: str,
39+
annotations: Optional[str],
40+
template_info: str,
41+
keywords: Optional[List[str]],
42+
):
43+
self.id = id
44+
self.name = name
45+
self.creator = creator
46+
self.creator_str = creator.full_identity
47+
self.created = created
48+
self.created_str = created.isoformat()
49+
self.description = description
50+
self.agent = agent
51+
self.annotations = annotations
52+
self.template_info = template_info
53+
self.keywords = keywords
54+
self.keywords_str = ", ".join(keywords)
55+
56+
@classmethod
57+
def from_project(cls, project: Project):
58+
"""Create view model from ``Project``."""
59+
template_info = ""
60+
61+
if project.template_source:
62+
if project.template_source == "renku":
63+
template_info = f"{project.template_id} ({project.template_version})"
64+
else:
65+
template_info = f"{project.template_source}@{project.template_ref}: {project.template_id}"
66+
67+
return cls(
68+
id=project.id,
69+
name=project.name,
70+
creator=project.creator,
71+
created=project.date_created,
72+
description=project.description,
73+
agent=project.agent_version,
74+
annotations=json.dumps([{"id": a.id, "body": a.body, "source": a.source} for a in project.annotations])
75+
if project.annotations
76+
else None,
77+
template_info=template_info,
78+
keywords=project.keywords,
79+
)

renku/core/management/repository.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ def with_metadata(
249249
read_only=False,
250250
name=None,
251251
description=None,
252+
keywords=None,
252253
custom_metadata=None,
253254
):
254255
"""Yield an editable metadata object."""
@@ -257,7 +258,7 @@ def with_metadata(
257258
project = project_gateway.get_project()
258259
except ValueError:
259260
project = Project.from_client(
260-
name=name, description=description, custom_metadata=custom_metadata, client=self
261+
name=name, description=description, keywords=keywords, custom_metadata=custom_metadata, client=self
261262
)
262263

263264
yield project

renku/core/models/project.py

+10-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
class Project(persistent.Persistent):
3737
"""Represent a project."""
3838

39+
keywords = None
40+
3941
def __init__(
4042
self,
4143
*,
@@ -54,6 +56,7 @@ def __init__(
5456
template_source: str = None,
5557
template_version: str = None,
5658
version: str = None,
59+
keywords: List[str] = None,
5760
):
5861
from renku.core.management.migrate import SUPPORTED_PROJECT_VERSION
5962

@@ -79,13 +82,15 @@ def __init__(
7982
self.template_source: str = template_source
8083
self.template_version: str = template_version
8184
self.version: str = version
85+
self.keywords: List[str] = keywords or []
8286

8387
@classmethod
8488
def from_client(
8589
cls,
8690
client,
8791
name: str = None,
8892
description: str = None,
93+
keywords: List[str] = None,
8994
custom_metadata: Dict = None,
9095
creator: Person = None,
9196
) -> "Project":
@@ -101,7 +106,9 @@ def from_client(
101106
raise ValueError("Project Creator not set")
102107

103108
id = cls.generate_id(namespace=namespace, name=name)
104-
return cls(creator=creator, id=id, name=name, description=description, annotations=annotations)
109+
return cls(
110+
creator=creator, id=id, name=name, description=description, keywords=keywords, annotations=annotations
111+
)
105112

106113
@staticmethod
107114
def get_namespace_and_name(*, client=None, name: str = None, creator: Person = None):
@@ -134,7 +141,7 @@ def generate_id(namespace: str, name: str):
134141

135142
def update_metadata(self, custom_metadata=None, **kwargs):
136143
"""Updates metadata."""
137-
editable_attributes = ["creator", "description"]
144+
editable_attributes = ["creator", "description", "keywords"]
138145
for name, value in kwargs.items():
139146
if name not in editable_attributes:
140147
raise errors.ParameterError(f"Cannot edit field: '{name}'")
@@ -174,3 +181,4 @@ class Meta:
174181
template_source = fields.String(renku.templateSource, missing=None)
175182
template_version = fields.String(renku.templateVersion, missing=None)
176183
version = StringList(schema.schemaVersion, missing="1")
184+
keywords = fields.List(schema.keywords, fields.String(), missing=None)

renku/data/shacl_shape.json

+7
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,13 @@
214214
"sh:class": {
215215
"@id": "prov:Activity"
216216
}
217+
},
218+
{
219+
"nodeKind": "sh:Literal",
220+
"path": "schema:keywords",
221+
"datatype": {
222+
"@id": "xsd:string"
223+
}
217224
}
218225
]
219226
},

renku/service/controllers/project_edit.py

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def renku_op(self):
5454
description=self.ctx.get("description"),
5555
creator=self.ctx.get("creator"),
5656
custom_metadata=self.ctx.get("custom_metadata"),
57+
keywords=self.ctx.get("keywords"),
5758
)
5859
)
5960

0 commit comments

Comments
 (0)