Skip to content

Commit 619e003

Browse files
authored
Merge pull request #949 from CitrineInformatics/feature/pne-241-data-manager-release
[PNE-241] Data manager release
2 parents a81506f + 0a85d27 commit 619e003

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1776
-492
lines changed

src/citrine/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "3.3.0"
1+
__version__ = "3.4.0"

src/citrine/_utils/functions.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,25 @@ def resource_path(*,
319319
new_url = base._replace(path='/'.join(path), query=query).geturl()
320320

321321
return format_escaped_url(new_url, *action, **kwargs, uid=uid)
322+
323+
324+
def _data_manager_deprecation_checks(session, project_id: UUID, team_id: UUID, obj_type: str):
325+
if team_id is None:
326+
if project_id is None:
327+
raise TypeError("Missing one required argument: team_id.")
328+
329+
warn(f"{obj_type} now belong to Teams, so the project_id parameter was deprecated in "
330+
"3.4.0, and will be removed in 4.0. Please provide the team_id instead.",
331+
DeprecationWarning)
332+
# avoiding a circular import
333+
from citrine.resources.project import Project
334+
team_id = Project.get_team_id_from_project_id(session=session, project_id=project_id)
335+
return team_id
336+
337+
338+
def _pad_positional_args(args, n):
339+
if len(args) > 0:
340+
warn("Positional arguments are deprecated and will be removed in v4.0. Please use keyword "
341+
"arguments instead.",
342+
DeprecationWarning)
343+
return args + (None, ) * (n - len(args))

src/citrine/jobs/job.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from typing import Union
44
from uuid import UUID
55

6-
from citrine._serialization.properties import Set as PropertySet, String, Object
76
from citrine._rest.resource import Resource
7+
from citrine._serialization.properties import Set as PropertySet, String, Object
88
from citrine._serialization import properties
99
from citrine._session import Session
1010
from citrine._utils.functions import format_escaped_url
@@ -59,9 +59,9 @@ class JobStatusResponse(Resource['JobStatusResponse']):
5959

6060

6161
def _poll_for_job_completion(session: Session,
62-
project_id: Union[UUID, str],
6362
job: Union[JobSubmissionResponse, UUID, str],
6463
*,
64+
team_id: Union[UUID, str],
6565
timeout: float = 2 * 60,
6666
polling_delay: float = 2.0,
6767
raise_errors: bool = True,
@@ -96,7 +96,7 @@ def _poll_for_job_completion(session: Session,
9696
job_id = job.job_id
9797
else:
9898
job_id = job # pragma: no cover
99-
path = format_escaped_url('projects/{}/execution/job-status', project_id)
99+
path = format_escaped_url('teams/{}/execution/job-status', team_id)
100100
params = {'job_id': job_id}
101101
start_time = time()
102102
while True:

src/citrine/resources/condition_template.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ def __str__(self):
5858
class ConditionTemplateCollection(AttributeTemplateCollection[ConditionTemplate]):
5959
"""A collection of condition templates."""
6060

61-
_path_template = 'projects/{project_id}/datasets/{dataset_id}/condition-templates'
62-
_dataset_agnostic_path_template = 'projects/{project_id}/condition-templates'
6361
_individual_key = 'condition_template'
6462
_collection_key = 'condition_templates'
6563
_resource = ConditionTemplate

src/citrine/resources/data_concepts.py

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Top-level class for all data concepts objects and collections thereof."""
2-
from abc import abstractmethod, ABC
32
import re
3+
from abc import abstractmethod, ABC
44
from typing import TypeVar, Type, List, Union, Optional, Iterator, Iterable
55
from uuid import UUID, uuid4
66

@@ -18,11 +18,11 @@
1818
from citrine._serialization.properties import UUID as PropertyUUID
1919
from citrine._serialization.serializable import Serializable
2020
from citrine._session import Session
21-
from citrine._utils.functions import scrub_none, replace_objects_with_links, \
22-
format_escaped_url
21+
from citrine._utils.functions import _data_manager_deprecation_checks, format_escaped_url, \
22+
_pad_positional_args, replace_objects_with_links, scrub_none
2323
from citrine.exceptions import BadRequest
24-
from citrine.resources.audit_info import AuditInfo
2524
from citrine.jobs.job import _poll_for_job_completion
25+
from citrine.resources.audit_info import AuditInfo
2626
from citrine.resources.response import Response
2727

2828
CITRINE_SCOPE = 'id'
@@ -202,28 +202,56 @@ class DataConceptsCollection(Collection[ResourceType], ABC):
202202
203203
Parameters
204204
----------
205-
project_id: UUID
206-
The uid of the project that this collection belongs to.
205+
team_id: UUID
206+
The uid of the team that this collection belongs to.
207207
dataset_id: UUID
208208
The uid of the dataset that this collection belongs to. If None then the collection
209-
ranges over all datasets in the project. Note that this is only allowed for certain
209+
ranges over all datasets in the team. Note that this is only allowed for certain
210210
actions. For example, you can use :func:`list_by_tag` to search over all datasets,
211211
but when using :func:`register` to upload or update an object, a dataset must be specified.
212212
session: Session
213213
The Citrine session used to connect to the database.
214214
215215
"""
216216

217-
def __init__(self, project_id: UUID, dataset_id: UUID, session: Session):
218-
self.project_id = project_id
219-
self.dataset_id = dataset_id
220-
self.session = session
217+
def __init__(self,
218+
*args,
219+
session: Session = None,
220+
dataset_id: Optional[UUID] = None,
221+
team_id: UUID = None,
222+
project_id: Optional[UUID] = None):
223+
# Handle positional arguments for backward compatibility
224+
args = _pad_positional_args(args, 3)
225+
self.project_id = project_id or args[0]
226+
self.dataset_id = dataset_id or args[1]
227+
self.session = session or args[2]
228+
if self.session is None:
229+
raise TypeError("Missing one required argument: session.")
230+
231+
self.team_id = _data_manager_deprecation_checks(
232+
session=self.session,
233+
project_id=self.project_id,
234+
team_id=team_id,
235+
obj_type="GEMD Objects")
221236

222237
@classmethod
223238
@abstractmethod
224239
def get_type(cls) -> Type[Serializable]:
225240
"""Return the resource type in the collection."""
226241

242+
@property
243+
def _path_template(self):
244+
collection_key = self._collection_key.replace("_", "-")
245+
return f'teams/{self.team_id}/datasets/{self.dataset_id}/{collection_key}'
246+
247+
# After Data Manager deprecation, both can use the `teams/...` path.
248+
@property
249+
def _dataset_agnostic_path_template(self):
250+
if self.project_id is None:
251+
return f'teams/{self.team_id}/{self._collection_key.replace("_","-")}'
252+
else:
253+
return f'projects/{self.project_id}/{self._collection_key.replace("_","-")}'
254+
227255
def build(self, data: dict) -> ResourceType:
228256
"""
229257
Build an object of type ResourceType from a serialized dictionary.
@@ -389,8 +417,11 @@ def register_all(self,
389417
Each object model as it now exists in the database.
390418
391419
"""
420+
# avoiding a circular import
392421
from citrine.resources.gemd_resource import GEMDResourceCollection
393-
gemd_collection = GEMDResourceCollection(self.project_id, self.dataset_id, self.session)
422+
gemd_collection = GEMDResourceCollection(team_id=self.team_id,
423+
dataset_id=self.dataset_id,
424+
session=self.session)
394425
return gemd_collection.register_all(
395426
models,
396427
dry_run=dry_run,
@@ -482,7 +513,7 @@ def async_update(self, model: ResourceType, *,
482513
job_id = response_json["job_id"]
483514

484515
if wait_for_response:
485-
self.poll_async_update_job(job_id, timeout=timeout,
516+
self.poll_async_update_job(job_id=job_id, timeout=timeout,
486517
polling_delay=polling_delay)
487518

488519
# That worked, return nothing or return the object
@@ -525,8 +556,11 @@ def poll_async_update_job(self, job_id: UUID, *, timeout: float = 2 * 60,
525556
526557
"""
527558
# Poll for job completion - this will raise an error if the job failed
528-
_poll_for_job_completion(self.session, self.project_id, job_id, timeout=timeout,
529-
polling_delay=polling_delay)
559+
_poll_for_job_completion(
560+
session=self.session,
561+
team_id=self.team_id,
562+
job=job_id, timeout=timeout,
563+
polling_delay=polling_delay)
530564

531565
# That worked, nothing returned in this case
532566
return None
@@ -675,8 +709,8 @@ def _get_relation(self, relation: str, uid: Union[UUID, str, LinkByUID, BaseEnti
675709
link = _make_link_by_uid(uid)
676710
raw_objects = self.session.cursor_paged_resource(
677711
self.session.get_resource,
678-
format_escaped_url('projects/{}/{}/{}/{}/{}',
679-
self.project_id,
712+
format_escaped_url('teams/{}/{}/{}/{}/{}',
713+
self.team_id,
680714
relation,
681715
link.scope,
682716
link.id,

0 commit comments

Comments
 (0)