opsml.projects.project
1# pylint: disable=invalid-envvar-value 2# Copyright (c) Shipt, Inc. 3# This source code is licensed under the MIT license found in the 4# LICENSE file in the root directory of this source tree. 5# pylint: disable=protected-access 6 7from contextlib import contextmanager 8from typing import Any, Dict, Iterator, List, Optional, Union, cast 9 10from opsml.cards.base import ArtifactCard 11from opsml.cards.project import ProjectCard 12from opsml.cards.run import RunCard 13from opsml.helpers.logging import ArtifactLogger 14from opsml.projects._run_manager import ActiveRunException, _RunManager 15from opsml.projects.active_run import ActiveRun, CardHandler 16from opsml.projects.types import ProjectInfo 17from opsml.registry import CardRegistries 18from opsml.registry.sql.base.client import ClientProjectCardRegistry 19from opsml.types import CardInfo, CardType, Metric, Metrics, Param, Params 20 21logger = ArtifactLogger.get_logger() 22 23 24class _ProjectRegistrar: 25 def __init__(self, project_info: ProjectInfo): 26 self._project_info = project_info 27 self.registries = CardRegistries() 28 29 @property 30 def project_registry(self) -> ClientProjectCardRegistry: 31 # both server and client registries are the same for methods 32 return cast(ClientProjectCardRegistry, self.registries.project._registry) 33 34 def register_project(self) -> int: 35 """ 36 Checks if the project name exists in the project registry. A ProjectCard is created if it 37 doesn't exist. 38 39 Returns: 40 project_id: int 41 """ 42 43 card = ProjectCard( 44 name=self._project_info.name, 45 repository=self._project_info.repository, 46 contact=self._project_info.contact, 47 ) 48 self.registries.project.register_card(card=card) 49 50 return card.project_id 51 52 53class OpsmlProject: 54 def __init__(self, info: ProjectInfo): 55 """ 56 Instantiates a project which creates cards, metrics and parameters to 57 the opsml registry via a "run" object. 58 59 If info.run_id is set, that run_id will be loaded as read only. In read 60 only mode, you can retrieve cards, metrics, and parameters, however you 61 cannot write new data. If you wish to record data/create a new run, you will 62 need to enter the run context. 63 64 In order to create new cards, you need to create a run using the `run` 65 context manager. 66 67 Example: 68 69 project: OpsmlProject = OpsmlProject( 70 ProjectInfo( 71 name="test-project", 72 # If run_id is omitted, a new run is created. 73 run_id="123ab123kaj8u8naskdfh813", 74 ) 75 ) 76 # the project is in "read only" mode. all read operations will work 77 for k, v in project.parameters: 78 logger.info("{} = {}", k, v) 79 80 # creating a project run 81 with project.run() as run: 82 # Now that the run context is entered, it's in read/write mode 83 # You can write cards, parameters, and metrics to the project. 84 run.log_parameter(key="my_param", value="12.34") 85 86 Args: 87 info: 88 Run information. if a run_id is given, that run is set 89 as the project's current run. 90 """ 91 # Set the run manager and project_id (creates ProjectCard if project doesn't exist) 92 registrar = _ProjectRegistrar(project_info=info) 93 94 # get project id or register new project 95 info.project_id = registrar.register_project() 96 97 # crete run manager 98 self._run_mgr = _RunManager(project_info=info, registries=registrar.registries) 99 100 @property 101 def run_id(self) -> str: 102 """Current run id associated with project""" 103 if self._run_mgr.run_id is not None: 104 return self._run_mgr.run_id 105 raise ValueError("Run id not set for current project") 106 107 @run_id.setter 108 def run_id(self, run_id: str) -> None: 109 """Set the run_id to use with the active project""" 110 self._run_mgr.run_id = run_id 111 112 @property 113 def project_id(self) -> int: 114 return self._run_mgr.project_id 115 116 @property 117 def project_name(self) -> str: 118 return self._run_mgr._project_info.name # pylint: disable=protected-access 119 120 @contextmanager 121 def run(self, run_name: Optional[str] = None) -> Iterator[ActiveRun]: 122 """ 123 Starts a new run for the project 124 125 Args: 126 run_name: 127 Optional run name 128 """ 129 130 try: 131 yield self._run_mgr.start_run(run_name=run_name) # self._run_mgr.active_run 132 133 except ActiveRunException as error: 134 logger.error("Run already active. Ending run.") 135 raise error 136 137 except Exception as error: 138 logger.error("Error encountered. Ending run. {}", error) 139 self._run_mgr.end_run() 140 raise error 141 142 self._run_mgr.end_run() 143 144 def load_card(self, registry_name: str, info: CardInfo) -> ArtifactCard: 145 """ 146 Loads an ArtifactCard. 147 148 Args: 149 registry_name: 150 Name of registry to load card from 151 info: 152 Card information to retrieve. `uid` takes precedence if it 153 exists. If the optional `version` is specified, that version 154 will be loaded. If it doesn't exist, the most recent ersion will 155 be loaded. 156 157 Returns 158 `ArtifactCard` 159 """ 160 card_type = CardType(registry_name.lower()).value 161 return CardHandler.load_card( 162 registries=self._run_mgr.registries, 163 registry_name=card_type, 164 info=info, 165 ) 166 167 def list_runs(self, limit: int = 100) -> List[Dict[str, Any]]: 168 """ 169 Lists all runs for the current project, sorted by timestamp 170 171 Returns: 172 List of RunCard 173 """ 174 logger.info("Listing runs for project {}", self.project_name) 175 176 project_runs = self._run_mgr.registries.run._registry.list_cards( # pylint: disable=protected-access 177 limit=limit, 178 query_terms={"project": self.project_name}, 179 ) 180 181 return sorted(project_runs, key=lambda k: k["timestamp"], reverse=True) 182 183 @property 184 def runcard(self) -> RunCard: 185 return cast(RunCard, self._run_mgr.registries.run.load_card(uid=self.run_id)) 186 187 @property 188 def metrics(self) -> Metrics: 189 runcard = self.runcard 190 runcard.load_metrics() 191 return runcard.metrics 192 193 def get_metric(self, name: str) -> Union[List[Metric], Metric]: 194 """ 195 Get metric by name 196 197 Args: 198 name: str 199 200 Returns: 201 List of Metric or Metric 202 203 """ 204 return self.runcard.get_metric(name=name) 205 206 @property 207 def parameters(self) -> Params: 208 return self.runcard.parameters 209 210 def get_parameter(self, name: str) -> Union[List[Param], Param]: 211 """ 212 Get param by name 213 214 Args: 215 name: str 216 217 Returns: 218 List of Param or Param 219 220 """ 221 return self.runcard.get_parameter(name=name) 222 223 @property 224 def tags(self) -> Dict[str, Union[str, int]]: 225 return self.runcard.tags 226 227 @property 228 def datacard_uids(self) -> List[str]: 229 """DataCards associated with the current run""" 230 return self.runcard.datacard_uids 231 232 @property 233 def modelcard_uids(self) -> List[str]: 234 """ModelCards associated with the current run""" 235 return self.runcard.modelcard_uids
54class OpsmlProject: 55 def __init__(self, info: ProjectInfo): 56 """ 57 Instantiates a project which creates cards, metrics and parameters to 58 the opsml registry via a "run" object. 59 60 If info.run_id is set, that run_id will be loaded as read only. In read 61 only mode, you can retrieve cards, metrics, and parameters, however you 62 cannot write new data. If you wish to record data/create a new run, you will 63 need to enter the run context. 64 65 In order to create new cards, you need to create a run using the `run` 66 context manager. 67 68 Example: 69 70 project: OpsmlProject = OpsmlProject( 71 ProjectInfo( 72 name="test-project", 73 # If run_id is omitted, a new run is created. 74 run_id="123ab123kaj8u8naskdfh813", 75 ) 76 ) 77 # the project is in "read only" mode. all read operations will work 78 for k, v in project.parameters: 79 logger.info("{} = {}", k, v) 80 81 # creating a project run 82 with project.run() as run: 83 # Now that the run context is entered, it's in read/write mode 84 # You can write cards, parameters, and metrics to the project. 85 run.log_parameter(key="my_param", value="12.34") 86 87 Args: 88 info: 89 Run information. if a run_id is given, that run is set 90 as the project's current run. 91 """ 92 # Set the run manager and project_id (creates ProjectCard if project doesn't exist) 93 registrar = _ProjectRegistrar(project_info=info) 94 95 # get project id or register new project 96 info.project_id = registrar.register_project() 97 98 # crete run manager 99 self._run_mgr = _RunManager(project_info=info, registries=registrar.registries) 100 101 @property 102 def run_id(self) -> str: 103 """Current run id associated with project""" 104 if self._run_mgr.run_id is not None: 105 return self._run_mgr.run_id 106 raise ValueError("Run id not set for current project") 107 108 @run_id.setter 109 def run_id(self, run_id: str) -> None: 110 """Set the run_id to use with the active project""" 111 self._run_mgr.run_id = run_id 112 113 @property 114 def project_id(self) -> int: 115 return self._run_mgr.project_id 116 117 @property 118 def project_name(self) -> str: 119 return self._run_mgr._project_info.name # pylint: disable=protected-access 120 121 @contextmanager 122 def run(self, run_name: Optional[str] = None) -> Iterator[ActiveRun]: 123 """ 124 Starts a new run for the project 125 126 Args: 127 run_name: 128 Optional run name 129 """ 130 131 try: 132 yield self._run_mgr.start_run(run_name=run_name) # self._run_mgr.active_run 133 134 except ActiveRunException as error: 135 logger.error("Run already active. Ending run.") 136 raise error 137 138 except Exception as error: 139 logger.error("Error encountered. Ending run. {}", error) 140 self._run_mgr.end_run() 141 raise error 142 143 self._run_mgr.end_run() 144 145 def load_card(self, registry_name: str, info: CardInfo) -> ArtifactCard: 146 """ 147 Loads an ArtifactCard. 148 149 Args: 150 registry_name: 151 Name of registry to load card from 152 info: 153 Card information to retrieve. `uid` takes precedence if it 154 exists. If the optional `version` is specified, that version 155 will be loaded. If it doesn't exist, the most recent ersion will 156 be loaded. 157 158 Returns 159 `ArtifactCard` 160 """ 161 card_type = CardType(registry_name.lower()).value 162 return CardHandler.load_card( 163 registries=self._run_mgr.registries, 164 registry_name=card_type, 165 info=info, 166 ) 167 168 def list_runs(self, limit: int = 100) -> List[Dict[str, Any]]: 169 """ 170 Lists all runs for the current project, sorted by timestamp 171 172 Returns: 173 List of RunCard 174 """ 175 logger.info("Listing runs for project {}", self.project_name) 176 177 project_runs = self._run_mgr.registries.run._registry.list_cards( # pylint: disable=protected-access 178 limit=limit, 179 query_terms={"project": self.project_name}, 180 ) 181 182 return sorted(project_runs, key=lambda k: k["timestamp"], reverse=True) 183 184 @property 185 def runcard(self) -> RunCard: 186 return cast(RunCard, self._run_mgr.registries.run.load_card(uid=self.run_id)) 187 188 @property 189 def metrics(self) -> Metrics: 190 runcard = self.runcard 191 runcard.load_metrics() 192 return runcard.metrics 193 194 def get_metric(self, name: str) -> Union[List[Metric], Metric]: 195 """ 196 Get metric by name 197 198 Args: 199 name: str 200 201 Returns: 202 List of Metric or Metric 203 204 """ 205 return self.runcard.get_metric(name=name) 206 207 @property 208 def parameters(self) -> Params: 209 return self.runcard.parameters 210 211 def get_parameter(self, name: str) -> Union[List[Param], Param]: 212 """ 213 Get param by name 214 215 Args: 216 name: str 217 218 Returns: 219 List of Param or Param 220 221 """ 222 return self.runcard.get_parameter(name=name) 223 224 @property 225 def tags(self) -> Dict[str, Union[str, int]]: 226 return self.runcard.tags 227 228 @property 229 def datacard_uids(self) -> List[str]: 230 """DataCards associated with the current run""" 231 return self.runcard.datacard_uids 232 233 @property 234 def modelcard_uids(self) -> List[str]: 235 """ModelCards associated with the current run""" 236 return self.runcard.modelcard_uids
55 def __init__(self, info: ProjectInfo): 56 """ 57 Instantiates a project which creates cards, metrics and parameters to 58 the opsml registry via a "run" object. 59 60 If info.run_id is set, that run_id will be loaded as read only. In read 61 only mode, you can retrieve cards, metrics, and parameters, however you 62 cannot write new data. If you wish to record data/create a new run, you will 63 need to enter the run context. 64 65 In order to create new cards, you need to create a run using the `run` 66 context manager. 67 68 Example: 69 70 project: OpsmlProject = OpsmlProject( 71 ProjectInfo( 72 name="test-project", 73 # If run_id is omitted, a new run is created. 74 run_id="123ab123kaj8u8naskdfh813", 75 ) 76 ) 77 # the project is in "read only" mode. all read operations will work 78 for k, v in project.parameters: 79 logger.info("{} = {}", k, v) 80 81 # creating a project run 82 with project.run() as run: 83 # Now that the run context is entered, it's in read/write mode 84 # You can write cards, parameters, and metrics to the project. 85 run.log_parameter(key="my_param", value="12.34") 86 87 Args: 88 info: 89 Run information. if a run_id is given, that run is set 90 as the project's current run. 91 """ 92 # Set the run manager and project_id (creates ProjectCard if project doesn't exist) 93 registrar = _ProjectRegistrar(project_info=info) 94 95 # get project id or register new project 96 info.project_id = registrar.register_project() 97 98 # crete run manager 99 self._run_mgr = _RunManager(project_info=info, registries=registrar.registries)
Instantiates a project which creates cards, metrics and parameters to the opsml registry via a "run" object.
If info.run_id is set, that run_id will be loaded as read only. In read only mode, you can retrieve cards, metrics, and parameters, however you cannot write new data. If you wish to record data/create a new run, you will need to enter the run context.
In order to create new cards, you need to create a run using the run
context manager.
Example:
project: OpsmlProject = OpsmlProject( ProjectInfo( name="test-project", # If run_id is omitted, a new run is created. run_id="123ab123kaj8u8naskdfh813", ) )
the project is in "read only" mode. all read operations will work
for k, v in project.parameters: logger.info("{} = {}", k, v)
creating a project run
with project.run() as run: # Now that the run context is entered, it's in read/write mode # You can write cards, parameters, and metrics to the project. run.log_parameter(key="my_param", value="12.34")
Arguments:
- info: Run information. if a run_id is given, that run is set as the project's current run.
101 @property 102 def run_id(self) -> str: 103 """Current run id associated with project""" 104 if self._run_mgr.run_id is not None: 105 return self._run_mgr.run_id 106 raise ValueError("Run id not set for current project")
Current run id associated with project
121 @contextmanager 122 def run(self, run_name: Optional[str] = None) -> Iterator[ActiveRun]: 123 """ 124 Starts a new run for the project 125 126 Args: 127 run_name: 128 Optional run name 129 """ 130 131 try: 132 yield self._run_mgr.start_run(run_name=run_name) # self._run_mgr.active_run 133 134 except ActiveRunException as error: 135 logger.error("Run already active. Ending run.") 136 raise error 137 138 except Exception as error: 139 logger.error("Error encountered. Ending run. {}", error) 140 self._run_mgr.end_run() 141 raise error 142 143 self._run_mgr.end_run()
Starts a new run for the project
Arguments:
- run_name: Optional run name
145 def load_card(self, registry_name: str, info: CardInfo) -> ArtifactCard: 146 """ 147 Loads an ArtifactCard. 148 149 Args: 150 registry_name: 151 Name of registry to load card from 152 info: 153 Card information to retrieve. `uid` takes precedence if it 154 exists. If the optional `version` is specified, that version 155 will be loaded. If it doesn't exist, the most recent ersion will 156 be loaded. 157 158 Returns 159 `ArtifactCard` 160 """ 161 card_type = CardType(registry_name.lower()).value 162 return CardHandler.load_card( 163 registries=self._run_mgr.registries, 164 registry_name=card_type, 165 info=info, 166 )
Loads an ArtifactCard.
Arguments:
- registry_name: Name of registry to load card from
- info: Card information to retrieve.
uid
takes precedence if it exists. If the optionalversion
is specified, that version will be loaded. If it doesn't exist, the most recent ersion will be loaded.
Returns
ArtifactCard
168 def list_runs(self, limit: int = 100) -> List[Dict[str, Any]]: 169 """ 170 Lists all runs for the current project, sorted by timestamp 171 172 Returns: 173 List of RunCard 174 """ 175 logger.info("Listing runs for project {}", self.project_name) 176 177 project_runs = self._run_mgr.registries.run._registry.list_cards( # pylint: disable=protected-access 178 limit=limit, 179 query_terms={"project": self.project_name}, 180 ) 181 182 return sorted(project_runs, key=lambda k: k["timestamp"], reverse=True)
Lists all runs for the current project, sorted by timestamp
Returns:
List of RunCard
194 def get_metric(self, name: str) -> Union[List[Metric], Metric]: 195 """ 196 Get metric by name 197 198 Args: 199 name: str 200 201 Returns: 202 List of Metric or Metric 203 204 """ 205 return self.runcard.get_metric(name=name)
Get metric by name
Arguments:
- name: str
Returns:
List of Metric or Metric
211 def get_parameter(self, name: str) -> Union[List[Param], Param]: 212 """ 213 Get param by name 214 215 Args: 216 name: str 217 218 Returns: 219 List of Param or Param 220 221 """ 222 return self.runcard.get_parameter(name=name)
Get param by name
Arguments:
- name: str
Returns:
List of Param or Param