code-loader 1.0.43a0__tar.gz → 1.0.44__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {code_loader-1.0.43a0 → code_loader-1.0.44}/PKG-INFO +1 -1
  2. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/__init__.py +2 -1
  3. code_loader-1.0.44/code_loader/experiment_api/api.py +81 -0
  4. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/cli_config_utils.py +3 -3
  5. code_loader-1.0.44/code_loader/experiment_api/client.py +34 -0
  6. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/epoch.py +12 -12
  7. code_loader-1.0.44/code_loader/experiment_api/experiment.py +49 -0
  8. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/experiment_context.py +2 -2
  9. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/utils.py +5 -4
  10. code_loader-1.0.44/code_loader/visualizers/__init__.py +0 -0
  11. {code_loader-1.0.43a0 → code_loader-1.0.44}/pyproject.toml +1 -1
  12. code_loader-1.0.43a0/code_loader/rt_api/__init__.py +0 -12
  13. code_loader-1.0.43a0/code_loader/rt_api/api_client.py +0 -107
  14. code_loader-1.0.43a0/code_loader/rt_api/experiment.py +0 -47
  15. {code_loader-1.0.43a0 → code_loader-1.0.44}/LICENSE +0 -0
  16. {code_loader-1.0.43a0 → code_loader-1.0.44}/README.md +0 -0
  17. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/__init__.py +0 -0
  18. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/datasetclasses.py +0 -0
  19. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/enums.py +0 -0
  20. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/exceptions.py +0 -0
  21. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/responsedataclasses.py +0 -0
  22. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/contract/visualizer_classes.py +0 -0
  23. {code_loader-1.0.43a0/code_loader/visualizers → code_loader-1.0.44/code_loader/experiment_api}/__init__.py +0 -0
  24. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/types.py +0 -0
  25. {code_loader-1.0.43a0/code_loader/rt_api → code_loader-1.0.44/code_loader/experiment_api}/workingspace_config_utils.py +0 -0
  26. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/inner_leap_binder/__init__.py +0 -0
  27. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/inner_leap_binder/leapbinder.py +0 -0
  28. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/leaploader.py +0 -0
  29. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/utils.py +0 -0
  30. {code_loader-1.0.43a0 → code_loader-1.0.44}/code_loader/visualizers/default_visualizers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: code-loader
3
- Version: 1.0.43a0
3
+ Version: 1.0.44
4
4
  Summary:
5
5
  Home-page: https://github.com/tensorleap/code-loader
6
6
  License: MIT
@@ -1,3 +1,4 @@
1
1
  from code_loader.leaploader import LeapLoader
2
2
  from code_loader.inner_leap_binder import global_leap_binder as leap_binder
3
- from code_loader.rt_api import Epoch, Experiment
3
+ from code_loader.experiment_api.experiment import init_experiment
4
+ from code_loader.experiment_api.client import Client
@@ -0,0 +1,81 @@
1
+
2
+ from dataclasses import dataclass
3
+ from typing import Dict, List, Optional, Any
4
+ from code_loader.experiment_api.client import Client
5
+ from code_loader.experiment_api.types import ApiMetrics
6
+
7
+
8
+ @dataclass
9
+ class StartExperimentRequest:
10
+ projectId: str
11
+ experimentName: str
12
+ description: str
13
+ removeUntaggedUploadedModels: bool = True
14
+ codeIntegrationVersionId: Optional[str] = None
15
+
16
+ @dataclass
17
+ class StartExperimentResponse:
18
+ projectId: str
19
+ versionId: str
20
+ experimentId: str
21
+
22
+ @dataclass
23
+ class GetUploadModelSignedUrlRequest:
24
+ epoch: int
25
+ experimentId: str
26
+ versionId: str
27
+ projectId: str
28
+ fileType: str
29
+ origin: Optional[str] = None
30
+
31
+ @dataclass
32
+ class GetUploadModelSignedUrlResponse:
33
+ url: str
34
+ fileName: str
35
+
36
+ @dataclass
37
+ class AddExternalEpochDataRequest:
38
+ projectId: str
39
+ experimentId: str
40
+ epoch: int
41
+ metrics: ApiMetrics
42
+ force: bool = False
43
+
44
+ @dataclass
45
+ class TagModelRequest:
46
+ projectId: str
47
+ experimentId: str
48
+ epoch: int
49
+ tags: List[str]
50
+
51
+ @dataclass
52
+ class SetExperimentNotesRequest:
53
+ projectId: str
54
+ experimentId: str
55
+ notes: Dict[str, Any]
56
+
57
+ class Api:
58
+ def __init__(self, client: Client):
59
+ self.client = client
60
+
61
+ def start_experiment(self, data: StartExperimentRequest) -> StartExperimentResponse:
62
+ response = self.client.post('/versions/startExperiment', data)
63
+ self.client.check_response(response)
64
+ return StartExperimentResponse(**response.json())
65
+
66
+ def get_uploaded_model_signed_url(self, data: GetUploadModelSignedUrlRequest)-> GetUploadModelSignedUrlResponse:
67
+ response = self.client.post('/versions/getUploadModelSignedUrl', data)
68
+ self.client.check_response(response)
69
+ return GetUploadModelSignedUrlResponse(**response.json())
70
+
71
+ def add_external_epoch_data(self, data: AddExternalEpochDataRequest)-> None:
72
+ response = self.client.post('/externalepochdata/addExternalEpochData', data)
73
+ self.client.check_response(response)
74
+
75
+ def tag_model(self, data: TagModelRequest)-> None:
76
+ response = self.client.post('/versions/tagModel', data)
77
+ self.client.check_response(response)
78
+
79
+ def set_experiment_notes(self, data: SetExperimentNotesRequest)-> None:
80
+ response = self.client.post('/versions/setExperimentNotes', data)
81
+ self.client.check_response(response)
@@ -22,14 +22,14 @@ def get_cli_conf_file() -> Optional[Config]:
22
22
  if not os.path.exists(cli_conf_path):
23
23
  return None
24
24
  with open(cli_conf_path) as f:
25
- y = yaml.safe_load(f)
26
- envs_dict = y.get("envs")
25
+ config_yaml = yaml.safe_load(f)
26
+ envs_dict = config_yaml.get("envs")
27
27
  if envs_dict is None:
28
28
  return None
29
29
  envs = dict()
30
30
  for k, v in envs_dict.items():
31
31
  envs[k] = AuthConfig(**v)
32
- return Config(envs=envs, current_env=y["current_env"])
32
+ return Config(envs=envs, current_env=config_yaml["current_env"])
33
33
 
34
34
  def get_auth_config() -> Optional[AuthConfig]:
35
35
  cli_conf = get_cli_conf_file()
@@ -0,0 +1,34 @@
1
+
2
+ from typing import Any, Dict, Optional
3
+ from code_loader.experiment_api.cli_config_utils import get_auth_config
4
+ from code_loader.experiment_api.utils import join_url, to_dict_no_none
5
+ import requests
6
+
7
+
8
+ class Client:
9
+ def __init__(self, url: Optional[str] = None, token: Optional[str] = None):
10
+ if url is None or token is None:
11
+ configAuth = get_auth_config()
12
+ if configAuth is None:
13
+ raise Exception("No auth config found, either provide url and token or use `leap auth [url] [token]` to setup a config file")
14
+ url = configAuth.api_url
15
+ token = configAuth.api_key
16
+
17
+ self.url = url
18
+ self.token = token
19
+
20
+ def __add_auth(self, headers: Dict[str, str]) -> Dict[str, str]:
21
+ headers['Authorization'] = f'Bearer {self.token}'
22
+ return headers
23
+
24
+ def post(self, post_path: str, data: Any, headers: Dict[str, str] = {})-> requests.Response:
25
+ headers = self.__add_auth(headers)
26
+ if 'Content-Type' not in headers:
27
+ headers['Content-Type'] = 'application/json'
28
+ url = join_url(self.url, post_path)
29
+ json_data = to_dict_no_none(data)
30
+ return requests.post(url, json=json_data, headers=headers)
31
+
32
+ def check_response(self, response: requests.Response)-> None:
33
+ if response.status_code >= 400:
34
+ raise Exception(f"Error: {response.status_code} {response.text}")
@@ -1,9 +1,9 @@
1
1
 
2
2
  from typing import List, Optional
3
- from code_loader.rt_api import ExperimentContext
4
- from code_loader.rt_api.types import Metrics
5
- from code_loader.rt_api.utils import to_api_metric_value, upload_file
6
- from .api_client import AddExternalEpochDataRequest, GetUploadModelSignedUrlRequest, TagModelRequest
3
+ from code_loader.experiment_api.experiment_context import ExperimentContext
4
+ from code_loader.experiment_api.types import Metrics
5
+ from code_loader.experiment_api.utils import to_api_metric_value, upload_file
6
+ from code_loader.experiment_api.api import AddExternalEpochDataRequest, GetUploadModelSignedUrlRequest, TagModelRequest
7
7
 
8
8
 
9
9
  class Epoch:
@@ -19,12 +19,12 @@ class Epoch:
19
19
  def set_metrics(self, metrics: Metrics)-> None:
20
20
  self.metrics = metrics
21
21
 
22
- def upload_model(self, modelFilePath: str)-> None:
22
+ def _upload_model(self, modelFilePath: str)-> None:
23
23
  allowed_extensions = ["h5", "onnx"]
24
24
  modelExtension = modelFilePath.split(".")[-1]
25
25
  if modelExtension not in allowed_extensions:
26
26
  raise Exception(f"Model file extension not allowed. Allowed extensions are {allowed_extensions}")
27
- url = self.ctx.client.get_attach_model_upload_signed_url(GetUploadModelSignedUrlRequest(
27
+ url = self.ctx.api.get_uploaded_model_signed_url(GetUploadModelSignedUrlRequest(
28
28
  epoch=self.epoch,
29
29
  experimentId=self.ctx.experiment_id,
30
30
  versionId=self.ctx.version_id,
@@ -35,29 +35,29 @@ class Epoch:
35
35
  upload_file(url.url, modelFilePath)
36
36
  print("Model file uploaded")
37
37
 
38
- def tag_model(self, tags: List[str])-> None:
38
+ def _tag_model(self, tags: List[str])-> None:
39
39
  print(f"Tagging epoch({self.epoch}) model")
40
- self.ctx.client.tag_model(TagModelRequest(
40
+ self.ctx.api.tag_model(TagModelRequest(
41
41
  experimentId=self.ctx.experiment_id,
42
42
  projectId=self.ctx.project_id,
43
43
  epoch=self.epoch,
44
44
  tags=tags
45
45
  ))
46
46
 
47
- def save(self, modelFilePath: Optional[str] = None, tags: List[str] = ['latest'])-> None:
47
+ def log(self, modelFilePath: Optional[str] = None, tags: List[str] = ['latest'])-> None:
48
48
  if modelFilePath is not None:
49
- self.upload_model(modelFilePath)
49
+ self._upload_model(modelFilePath)
50
50
 
51
51
  print(f"Add metrics for epoch({self.epoch}) model")
52
52
  api_metrics ={
53
53
  key: to_api_metric_value(value) for key, value in self.metrics.items()
54
54
  }
55
- self.ctx.client.add_external_epoch_data(AddExternalEpochDataRequest(
55
+ self.ctx.api.add_external_epoch_data(AddExternalEpochDataRequest(
56
56
  experimentId=self.ctx.experiment_id,
57
57
  projectId=self.ctx.project_id,
58
58
  epoch=self.epoch,
59
59
  metrics=api_metrics
60
60
  ))
61
61
  if modelFilePath is not None and len(tags) > 0:
62
- self.tag_model(tags)
62
+ self._tag_model(tags)
63
63
 
@@ -0,0 +1,49 @@
1
+
2
+ from typing import Any, Dict, List, Optional
3
+ from code_loader.experiment_api.epoch import Epoch
4
+ from code_loader.experiment_api.api import Api, SetExperimentNotesRequest, StartExperimentRequest
5
+ from code_loader.experiment_api.experiment_context import ExperimentContext
6
+ from code_loader.experiment_api.types import Metrics
7
+ from code_loader.experiment_api.workingspace_config_utils import load_workspace_config
8
+ from code_loader.experiment_api.client import Client
9
+
10
+
11
+ class Experiment:
12
+ def __init__(self, ctx: ExperimentContext):
13
+ self.ctx = ctx
14
+
15
+ def init_epoch(self, epoch: int) -> Epoch:
16
+ return Epoch(self.ctx, epoch)
17
+
18
+ def log_epoch(self, epoch: int, metrics: Optional[Metrics] = None, model_path: Optional[str] = None, tags: List[str] = ['latest'])-> None:
19
+ epoch_o = self.init_epoch(epoch)
20
+ if metrics is not None:
21
+ epoch_o.set_metrics(metrics)
22
+ epoch_o.log(model_path, tags)
23
+
24
+ def set_notes(self, notes: Dict[str, Any])-> None:
25
+ print(f"Setting experiment({self.ctx.experiment_id}) notes")
26
+ self.ctx.api.set_experiment_notes(SetExperimentNotesRequest(
27
+ experimentId=self.ctx.experiment_id,
28
+ projectId=self.ctx.project_id,
29
+ notes=notes
30
+ ))
31
+
32
+ def init_experiment(experimentName: str, description: str, working_dir: Optional[str] = None, client: Optional[Client] = None) -> 'Experiment':
33
+ if client is None:
34
+ client = Client()
35
+
36
+ api = Api(client)
37
+
38
+ workspace_config = load_workspace_config(working_dir)
39
+ if workspace_config is None or workspace_config.projectId is None:
40
+ raise Exception("No leap workspace config found or projectId is missing, make sure you are in a leap workspace directory or provide a working_dir")
41
+
42
+ result = api.start_experiment(StartExperimentRequest(
43
+ projectId=workspace_config.projectId,
44
+ experimentName=experimentName,
45
+ description=description,
46
+ codeIntegrationVersionId=workspace_config.codeIntegrationId
47
+ ))
48
+ ctx = ExperimentContext(api, result.projectId, result.versionId, result.experimentId)
49
+ return Experiment(ctx)
@@ -1,10 +1,10 @@
1
1
  from dataclasses import dataclass
2
- from code_loader.rt_api.api_client import ApiClient
2
+ from code_loader.experiment_api.api import Api
3
3
 
4
4
 
5
5
  @dataclass
6
6
  class ExperimentContext:
7
- client: ApiClient
7
+ api: Api
8
8
  project_id: str
9
9
  version_id: str
10
10
  experiment_id: str
@@ -1,20 +1,21 @@
1
1
  from dataclasses import asdict, is_dataclass
2
- from typing import Dict
2
+ from typing import Any, Dict, Union
3
3
  from urllib.parse import urljoin
4
- from code_loader.rt_api.types import ApiMetricValue, MetricValue, NumericMetricValue, StringMetricValue
4
+ from code_loader.experiment_api.types import ApiMetricValue, MetricValue, NumericMetricValue, StringMetricValue
5
5
  import requests
6
6
 
7
+
7
8
  def upload_file(url: str, file_path: str)-> None:
8
9
  with open(file_path, "rb") as f:
9
10
  requests.put(url, data=f, timeout=12_000)
10
11
 
11
- def to_dict_no_none(data: any)-> Dict[str, any]: # type: ignore[valid-type]
12
+ def to_dict_no_none(data: Any)-> Union[Dict[str, Any], Any]:
12
13
  if is_dataclass(data):
13
14
  data = asdict(data)
14
15
  if isinstance(data, dict):
15
16
  return {k: to_dict_no_none(v) for k, v in data.items() if v is not None}
16
17
  elif isinstance(data, list):
17
- return [to_dict_no_none(item) for item in data if item is not None]
18
+ return [to_dict_no_none(item) for item in data]
18
19
  else:
19
20
  return data
20
21
 
File without changes
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "code-loader"
3
- version = "1.0.43a0"
3
+ version = "1.0.44"
4
4
  description = ""
5
5
  authors = ["dorhar <doron.harnoy@tensorleap.ai>"]
6
6
  license = "MIT"
@@ -1,12 +0,0 @@
1
-
2
- from code_loader.rt_api.experiment_context import ExperimentContext
3
- from code_loader.rt_api.epoch import Epoch
4
- from code_loader.rt_api.experiment import Experiment
5
- from code_loader.rt_api.api_client import ApiClient
6
-
7
- __all__ = [
8
- 'ExperimentContext',
9
- 'Epoch',
10
- 'Experiment',
11
- 'ApiClient'
12
- ]
@@ -1,107 +0,0 @@
1
-
2
- from dataclasses import dataclass
3
- from typing import Dict, List, Optional
4
- from code_loader.rt_api.types import ApiMetrics
5
- from code_loader.rt_api.utils import join_url, to_dict_no_none
6
- from .cli_config_utils import get_auth_config
7
- import requests
8
-
9
-
10
- @dataclass
11
- class StartExperimentRequest:
12
- projectId: str
13
- experimentName: str
14
- description: str
15
- removeUntaggedUploadedModels: bool = True
16
- codeIntegrationVersionId: Optional[str] = None
17
-
18
- @dataclass
19
- class StartExperimentResponse:
20
- projectId: str
21
- versionId: str
22
- experimentId: str
23
-
24
- @dataclass
25
- class GetUploadModelSignedUrlRequest:
26
- epoch: int
27
- experimentId: str
28
- versionId: str
29
- projectId: str
30
- fileType: str
31
- origin: Optional[str] = None
32
-
33
- @dataclass
34
- class GetUploadModelSignedUrlResponse:
35
- url: str
36
- fileName: str
37
-
38
- @dataclass
39
- class AddExternalEpochDataRequest:
40
- projectId: str
41
- experimentId: str
42
- epoch: int
43
- metrics: ApiMetrics
44
- force: bool = False
45
-
46
- @dataclass
47
- class TagModelRequest:
48
- projectId: str
49
- experimentId: str
50
- epoch: int
51
- tags: List[str]
52
-
53
- @dataclass
54
- class SetExperimentNotesRequest:
55
- projectId: str
56
- experimentId: str
57
- notes: Dict[str, any] # type: ignore[valid-type]
58
-
59
- class ApiClient:
60
- def __init__(self, url: Optional[str] = None, token: Optional[str] = None):
61
- if url is None or token is None:
62
- configAuth = get_auth_config()
63
- if configAuth is None:
64
- raise Exception("No auth config found, either provide url and token or use `leap auth [url] [token]` to setup a config file")
65
- url = configAuth.api_url
66
- token = configAuth.api_key
67
-
68
- self.url = url
69
- self.token = token
70
-
71
- def __add_auth(self, headers: Dict[str, str]) -> Dict[str, str]:
72
- headers['Authorization'] = f'Bearer {self.token}'
73
- return headers
74
-
75
- def __post(self, post_path: str, data: any, headers: Dict[str, str] = {})-> requests.Response: # type: ignore[valid-type]
76
- headers = self.__add_auth(headers)
77
- if 'Content-Type' not in headers:
78
- headers['Content-Type'] = 'application/json'
79
- url = join_url(self.url, post_path)
80
- json_data = to_dict_no_none(data)
81
- return requests.post(url, json=json_data, headers=headers)
82
-
83
- def __check_response(self, response: requests.Response)-> None:
84
- if response.status_code >= 400:
85
- raise Exception(f"Error: {response.status_code} {response.text}")
86
-
87
- def start_experiment(self, data: StartExperimentRequest) -> StartExperimentResponse:
88
- response = self.__post('/versions/startExperiment', data)
89
- self.__check_response(response)
90
- return StartExperimentResponse(**response.json())
91
-
92
- def get_attach_model_upload_signed_url(self, data: GetUploadModelSignedUrlRequest)-> GetUploadModelSignedUrlResponse:
93
- response = self.__post('/versions/getUploadModelSignedUrl', data)
94
- self.__check_response(response)
95
- return GetUploadModelSignedUrlResponse(**response.json())
96
-
97
- def add_external_epoch_data(self, data: AddExternalEpochDataRequest)-> None:
98
- response = self.__post('/externalepochdata/addExternalEpochData', data)
99
- self.__check_response(response)
100
-
101
- def tag_model(self, data: TagModelRequest)-> None:
102
- response = self.__post('/versions/tagModel', data)
103
- self.__check_response(response)
104
-
105
- def set_experiment_notes(self, data: SetExperimentNotesRequest)-> None:
106
- response = self.__post('/versions/setExperimentNotes', data)
107
- self.__check_response(response)
@@ -1,47 +0,0 @@
1
-
2
- from typing import Dict, List, Optional
3
- from code_loader.rt_api import Epoch, ExperimentContext
4
- from code_loader.rt_api.types import Metrics
5
- from code_loader.rt_api.workingspace_config_utils import load_workspace_config
6
- from .api_client import SetExperimentNotesRequest, StartExperimentRequest, ApiClient
7
-
8
-
9
- class Experiment:
10
- def __init__(self, ctx: ExperimentContext):
11
- self.ctx = ctx
12
-
13
- def start_epoch(self, epoch: int) -> Epoch:
14
- return Epoch(self.ctx, epoch)
15
-
16
- def add_epoch(self, epoch: int, metrics: Optional[Metrics] = None, model_path: Optional[str] = None, tags: List[str] = ['latest'])-> None:
17
- epoch_o = self.start_epoch(epoch)
18
- if metrics is not None:
19
- epoch_o.set_metrics(metrics)
20
- epoch_o.save(model_path, tags)
21
-
22
- def set_notes(self, notes: Dict[str, any])-> None: # type: ignore[valid-type]
23
- print(f"Setting experiment({self.ctx.experiment_id}) notes")
24
- self.ctx.client.set_experiment_notes(SetExperimentNotesRequest(
25
- experimentId=self.ctx.experiment_id,
26
- projectId=self.ctx.project_id,
27
- notes=notes
28
- ))
29
-
30
- @staticmethod
31
- def Start(experimentName: str, description: str, working_dir: Optional[str] = None, client: Optional[ApiClient] = None) -> 'Experiment':
32
-
33
- if client is None:
34
- client = ApiClient()
35
-
36
- workspace_config = load_workspace_config(working_dir)
37
- if workspace_config is None or workspace_config.projectId is None:
38
- raise Exception("No leap workspace config found or projectId is missing, make sure you are in a leap workspace directory or provide a working_dir")
39
-
40
- result = client.start_experiment(StartExperimentRequest(
41
- projectId=workspace_config.projectId,
42
- experimentName=experimentName,
43
- description=description,
44
- codeIntegrationVersionId=workspace_config.codeIntegrationId
45
- ))
46
- ctx = ExperimentContext(client, result.projectId, result.versionId, result.experimentId)
47
- return Experiment(ctx)
File without changes
File without changes