synapse-sdk 0.1.1a0__tar.gz → 1.0.0a0__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.

Potentially problematic release.


This version of synapse-sdk might be problematic. Click here for more details.

Files changed (66) hide show
  1. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/PKG-INFO +3 -1
  2. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/pyproject.toml +2 -0
  3. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/requirements.txt +2 -0
  4. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/plugins/__init__.py +15 -8
  5. synapse_sdk-1.0.0a0/synapse/plugins/categories/base.py +185 -0
  6. synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation/actions/validation.py +10 -0
  7. synapse_sdk-1.0.0a0/synapse/plugins/categories/decorators.py +13 -0
  8. synapse_sdk-1.0.0a0/synapse/plugins/categories/export/actions/export.py +10 -0
  9. synapse_sdk-1.0.0a0/synapse/plugins/categories/import/actions/import.py +10 -0
  10. synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/deployment.py +23 -0
  11. synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/inference.py +10 -0
  12. synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions/test.py +10 -0
  13. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/plugins/categories/neural_net/actions/train.py +6 -1
  14. synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/__init__.py +0 -0
  15. synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/actions/__init__.py +0 -0
  16. synapse_sdk-1.0.0a0/synapse/plugins/categories/post_annotation/actions/post_annotation.py +10 -0
  17. synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/__init__.py +0 -0
  18. synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/actions/__init__.py +0 -0
  19. synapse_sdk-1.0.0a0/synapse/plugins/categories/pre_annotation/actions/pre_annotation.py +10 -0
  20. synapse_sdk-1.0.0a0/synapse/plugins/categories/registry.py +16 -0
  21. synapse_sdk-1.0.0a0/synapse/plugins/enums.py +16 -0
  22. synapse_sdk-1.0.0a0/synapse/plugins/job.py +5 -0
  23. synapse_sdk-1.0.0a0/synapse/plugins/upload.py +79 -0
  24. synapse_sdk-1.0.0a0/synapse/plugins/utils.py +40 -0
  25. synapse_sdk-1.0.0a0/synapse/utils/__init__.py +0 -0
  26. synapse_sdk-1.0.0a0/synapse/utils/debug.py +2 -0
  27. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/PKG-INFO +3 -1
  28. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/SOURCES.txt +18 -2
  29. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/requires.txt +2 -0
  30. synapse_sdk-0.1.1a0/synapse/plugins/categories/__init__.py +0 -11
  31. synapse_sdk-0.1.1a0/synapse/plugins/categories/base.py +0 -49
  32. synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions/deployment.py +0 -24
  33. synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions/test.py +0 -6
  34. synapse_sdk-0.1.1a0/synapse/plugins/utils.py +0 -26
  35. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.github/workflows/lint.yml +0 -0
  36. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.github/workflows/pypi-publish.yml +0 -0
  37. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.gitignore +0 -0
  38. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/.pre-commit-config.yaml +0 -0
  39. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/LICENSE +0 -0
  40. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/README.md +0 -0
  41. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/setup.cfg +0 -0
  42. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/__init__.py +0 -0
  43. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/__init__.py +0 -0
  44. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/exceptions.py +0 -0
  45. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/__init__.py +0 -0
  46. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/annotation.py +0 -0
  47. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/dataset.py +0 -0
  48. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/integration.py +0 -0
  49. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/mixins/ml.py +0 -0
  50. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/client/utils.py +0 -0
  51. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/config.py +0 -0
  52. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/loggers.py +0 -0
  53. {synapse_sdk-0.1.1a0/synapse/plugins/categories/custom_script → synapse_sdk-1.0.0a0/synapse/plugins/categories}/__init__.py +0 -0
  54. {synapse_sdk-0.1.1a0/synapse/plugins/categories/custom_script/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation}/__init__.py +0 -0
  55. {synapse_sdk-0.1.1a0/synapse/plugins/categories/export → synapse_sdk-1.0.0a0/synapse/plugins/categories/data_validation/actions}/__init__.py +0 -0
  56. {synapse_sdk-0.1.1a0/synapse/plugins/categories/export/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/export}/__init__.py +0 -0
  57. {synapse_sdk-0.1.1a0/synapse/plugins/categories/import → synapse_sdk-1.0.0a0/synapse/plugins/categories/export/actions}/__init__.py +0 -0
  58. {synapse_sdk-0.1.1a0/synapse/plugins/categories/import/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/import}/__init__.py +0 -0
  59. {synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net → synapse_sdk-1.0.0a0/synapse/plugins/categories/import/actions}/__init__.py +0 -0
  60. {synapse_sdk-0.1.1a0/synapse/plugins/categories/neural_net/actions → synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net}/__init__.py +0 -0
  61. {synapse_sdk-0.1.1a0/synapse/utils → synapse_sdk-1.0.0a0/synapse/plugins/categories/neural_net/actions}/__init__.py +0 -0
  62. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/file.py +0 -0
  63. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/module_loading.py +0 -0
  64. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse/utils/string.py +0 -0
  65. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/dependency_links.txt +0 -0
  66. {synapse_sdk-0.1.1a0 → synapse_sdk-1.0.0a0}/synapse_sdk.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synapse-sdk
3
- Version: 0.1.1a0
3
+ Version: 1.0.0a0
4
4
  Summary: synapse sdk
5
5
  Author-email: datamaker <developer@datamaker.io>
6
6
  License: MIT
@@ -8,8 +8,10 @@ Classifier: Programming Language :: Python :: 3
8
8
  Requires-Python: >=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
+ Requires-Dist: boto3
11
12
  Requires-Dist: requests
12
13
  Requires-Dist: tqdm
14
+ Requires-Dist: python-dotenv
13
15
  Requires-Dist: pyyaml
14
16
  Requires-Dist: pydantic
15
17
  Requires-Dist: ray[all]
@@ -13,8 +13,10 @@ classifiers = [
13
13
  'Programming Language :: Python :: 3',
14
14
  ]
15
15
  dependencies = [
16
+ 'boto3',
16
17
  'requests',
17
18
  'tqdm',
19
+ 'python-dotenv',
18
20
  'pyyaml',
19
21
  'pydantic',
20
22
  'ray[all]'
@@ -1,5 +1,7 @@
1
+ boto3
1
2
  requests
2
3
  tqdm
3
4
  pyyaml
4
5
  pydantic
6
+ python-dotenv
5
7
  ray[all]==2.38.0
@@ -1,17 +1,23 @@
1
1
  import argparse
2
+ import os
3
+
4
+ from dotenv import load_dotenv
2
5
 
3
6
  from synapse.plugins.utils import get_action
4
7
 
8
+
5
9
  action = None
6
10
 
7
11
 
8
- def init():
12
+ def run():
9
13
  global action
10
14
  parser = argparse.ArgumentParser(description='synapse plugin runner')
11
15
 
12
16
  # Add arguments
13
17
  parser.add_argument('action', help='action to run on this plugin')
14
18
  parser.add_argument('params', help='parameter of the action')
19
+ parser.add_argument('--direct', help='run without using ray', action='store_true')
20
+ parser.add_argument('--debug', help='run with debug mode', action='store_true')
15
21
 
16
22
  # Parse arguments
17
23
  args = parser.parse_args()
@@ -19,14 +25,15 @@ def init():
19
25
  # Access parsed arguments
20
26
  action = args.action
21
27
  params = args.params
28
+ direct = args.direct
29
+ debug = args.debug
22
30
 
23
- action = get_action(action, params)
31
+ load_dotenv(os.path.join(os.getcwd(), '.env'))
24
32
 
25
-
26
- def run():
27
- global action
28
- assert action is not None
29
- action.run()
33
+ action = get_action(action, params, direct=direct, debug=debug)
34
+ result = action.run_action()
35
+ if debug:
36
+ print(result)
30
37
 
31
38
 
32
- __all__ = ['init', 'run']
39
+ __all__ = ['run']
@@ -0,0 +1,185 @@
1
+ import inspect
2
+ import json
3
+ import os
4
+ from functools import cached_property
5
+ from pprint import pprint
6
+
7
+ import ray
8
+ import requests
9
+ from ray.dashboard.modules.job.sdk import JobSubmissionClient
10
+
11
+ from synapse.loggers import ConsoleLogger
12
+ from synapse.plugins.enums import RunMethod
13
+ from synapse.plugins.upload import upload_path, build_and_upload
14
+ from synapse.plugins.utils import get_plugin_checksum
15
+ from synapse.utils.module_loading import import_string
16
+
17
+
18
+ class Action:
19
+ name = None
20
+ category = None
21
+ method = None
22
+ params = None
23
+ plugin_config = None
24
+ config = None
25
+ client = None
26
+ logger = None
27
+ debug = False
28
+
29
+ default_envs = [
30
+ 'RAY_SERVE_ADDRESS',
31
+ 'SYNAPSE_PLUGIN_URL',
32
+ 'SYNAPSE_PLUGIN_PATH',
33
+ 'SYNAPSE_PLUGIN_BASE_URL',
34
+ 'SYNAPSE_PLUGIN_UPLOAD_S3_ENDPOINT_URL',
35
+ 'SYNAPSE_PLUGIN_UPLOAD_S3_BUCKET_NAME',
36
+ 'SYNAPSE_PLUGIN_UPLOAD_S3_ACCESS_KEY',
37
+ 'SYNAPSE_PLUGIN_UPLOAD_S3_SECRET_KEY',
38
+ 'SYNAPSE_PLUGIN_UPLOAD_S3_BASE_URL',
39
+ 'SYNAPSE_DEBUG_MODULES',
40
+ ]
41
+
42
+ def __init__(self, params, plugin_config, envs=None, job_id=None, direct=False, debug=False):
43
+ self.params = params
44
+ self.plugin_config = plugin_config
45
+ self.config = plugin_config['actions'][self.name]
46
+ self.job_id = job_id
47
+ self.direct = direct
48
+ self.debug = debug
49
+ if envs:
50
+ self.envs = {**envs, **self.get_default_envs()}
51
+ else:
52
+ self.envs = self.get_default_envs()
53
+
54
+ # TODO logger 지정 방식 개선
55
+ self.logger = ConsoleLogger()
56
+
57
+ @cached_property
58
+ def plugin_id(self):
59
+ code = self.plugin_config['code']
60
+ version = self.plugin_config['version']
61
+ return f'{code}@{version}'
62
+
63
+ @cached_property
64
+ def plugin_checksum(self):
65
+ return get_plugin_checksum(self.plugin_id)
66
+
67
+ @cached_property
68
+ def plugin_url(self):
69
+ if self.debug:
70
+ plugin_url = self.envs.get('SYNAPSE_PLUGIN_URL')
71
+ if not plugin_url:
72
+ plugin_url = upload_path(self.envs.get('SYNAPSE_PLUGIN_PATH', '.'), **self.get_kwargs_upload_path())
73
+ self.envs['SYNAPSE_PLUGIN_URL'] = plugin_url
74
+ return plugin_url
75
+ base_url = self.envs['SYNAPSE_PLUGIN_BASE_URL']
76
+ return str(os.path.join(base_url, f'{self.plugin_checksum}.zip'))
77
+
78
+ @cached_property
79
+ def entrypoint(self):
80
+ return import_string(self.config['entrypoint'])
81
+
82
+ def get_kwargs_upload_path(self):
83
+ # TODO upload 관련 env 단일화 후 제거
84
+ return {
85
+ 'endpoint_url': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_ENDPOINT_URL'],
86
+ 'bucket_name': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_BUCKET_NAME'],
87
+ 'access_key': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_ACCESS_KEY'],
88
+ 'secret_key': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_SECRET_KEY'],
89
+ 'base_url': self.envs['SYNAPSE_PLUGIN_UPLOAD_S3_BASE_URL'],
90
+ }
91
+
92
+ def get_default_envs(self):
93
+ return {env: os.environ[env] for env in self.default_envs if env in os.environ}
94
+
95
+ def get_debug_modules(self):
96
+ debug_modules = []
97
+ for module_path in self.envs.get('SYNAPSE_DEBUG_MODULES', '').split(','):
98
+ if module_path.startswith('http'):
99
+ module_url = module_path
100
+ else:
101
+ module_url = build_and_upload(module_path, **self.get_kwargs_upload_path())
102
+ debug_modules.append(module_url)
103
+ self.envs['SYNAPSE_DEBUG_MODULES'] = ','.join(debug_modules)
104
+ return debug_modules
105
+
106
+ def get_runtime_env(self):
107
+ runtime_env = {
108
+ 'pip': ['-r ${RAY_RUNTIME_ENV_CREATE_WORKING_DIR}/requirements.txt'],
109
+ 'working_dir': self.plugin_url,
110
+ }
111
+
112
+ if self.debug:
113
+ runtime_env['pip'] += self.get_debug_modules()
114
+
115
+ runtime_env['env_vars'] = self.envs
116
+ pprint(runtime_env)
117
+ return runtime_env
118
+
119
+ def run(self):
120
+ return self.entrypoint(self, **self.params)
121
+
122
+ def run_action(self):
123
+ if self.direct:
124
+ if self.method == RunMethod.RESTAPI:
125
+ return self.run_by_restapi()
126
+ else:
127
+ return self.run()
128
+ return getattr(self, f'run_by_{self.method.value}')()
129
+
130
+ def run_by_task(self):
131
+ @ray.remote(runtime_env=self.get_runtime_env())
132
+ def run_task(category, action, *args, **kwargs):
133
+ from synapse.plugins.utils import get_action_class
134
+
135
+ action = get_action_class(category, action)(*args, **kwargs)
136
+ return action.run_action()
137
+
138
+ init_signature = inspect.signature(self.__class__.__init__)
139
+
140
+ args = []
141
+ kwargs = {}
142
+
143
+ for param in init_signature.parameters.values():
144
+ if param.name == 'self':
145
+ continue
146
+ if param.default == param.empty:
147
+ args.append(getattr(self, param.name))
148
+ else:
149
+ kwargs[param.name] = getattr(self, param.name)
150
+
151
+ kwargs['direct'] = True
152
+ return ray.get(run_task.remote(self.category.value, self.name, *args, **kwargs))
153
+
154
+ def run_by_job(self):
155
+ entrypoint_args = [self.name, f'"{json.dumps(self.params)}"']
156
+ if self.debug:
157
+ entrypoint_args.append('--debug')
158
+
159
+ client = JobSubmissionClient()
160
+ return client.submit_job(
161
+ submission_id=self.job_id,
162
+ entrypoint=f'python main.py {" ".join(entrypoint_args)} --direct',
163
+ runtime_env=self.get_runtime_env(),
164
+ )
165
+
166
+ def run_by_restapi(self):
167
+ path = self.params.pop('path', '')
168
+ method = self.params.pop('method')
169
+
170
+ url = os.path.join(self.envs['RAY_SERVE_ADDRESS'], self.plugin_checksum, path)
171
+ response = getattr(requests, method)(url, **self.params)
172
+ # TODO ok response가 아닌 경우 대응하기
173
+ return response.json()
174
+
175
+ def set_progress(self, current, total, category=''):
176
+ self.logger.set_progress(current, total, category)
177
+
178
+ def log(self, action, data):
179
+ self.logger.log(action, data)
180
+
181
+ def log_event(self, message):
182
+ self.logger.log('event', {'content': message})
183
+
184
+ def end_log(self):
185
+ self.log_event('Plugin run is complete.')
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class ValidationAction(Action):
8
+ name = 'validation'
9
+ category = PluginCategory.DATA_VALIDATION
10
+ method = RunMethod.TASK
@@ -0,0 +1,13 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.registry import _REGISTERED_ACTIONS
3
+
4
+
5
+ def register_action(action_class):
6
+ if not issubclass(action_class, Action):
7
+ raise ValueError('Wrapped class must subclass Action class.')
8
+
9
+ try:
10
+ _REGISTERED_ACTIONS[action_class.category.value][action_class.name] = action_class
11
+ except KeyError:
12
+ _REGISTERED_ACTIONS[action_class.category.value] = {action_class.name: action_class}
13
+ return action_class
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class ExportAction(Action):
8
+ name = 'export'
9
+ category = PluginCategory.EXPORT
10
+ method = RunMethod.JOB
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class ImportAction(Action):
8
+ name = 'import'
9
+ category = PluginCategory.IMPORT
10
+ method = RunMethod.JOB
@@ -0,0 +1,23 @@
1
+ from ray import serve
2
+
3
+ from synapse.plugins.categories.base import Action
4
+ from synapse.plugins.categories.decorators import register_action
5
+ from synapse.plugins.enums import PluginCategory, RunMethod
6
+
7
+
8
+ @register_action
9
+ class DeploymentAction(Action):
10
+ name = 'deployment'
11
+ category = PluginCategory.NEURAL_NET
12
+ method = RunMethod.JOB
13
+
14
+ def get_deployment(self):
15
+ return serve.deployment(ray_actor_options=self.get_actor_options())(self.entrypoint)
16
+
17
+ def get_actor_options(self):
18
+ return {'runtime_env': self.get_runtime_env()}
19
+
20
+ def run(self):
21
+ deployment = self.get_deployment()
22
+ serve.delete(self.plugin_id)
23
+ serve.run(deployment.bind(), name=self.plugin_id, route_prefix=f'/{self.plugin_checksum}')
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class InferenceAction(Action):
8
+ name = 'inference'
9
+ category = PluginCategory.NEURAL_NET
10
+ method = RunMethod.RESTAPI
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class TestAction(Action):
8
+ name = 'test'
9
+ category = PluginCategory.NEURAL_NET
10
+ method = RunMethod.TASK
@@ -1,10 +1,15 @@
1
1
  from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
2
4
  from synapse.utils.file import get_dict_from_file, files_url_to_path_from_objs
3
5
  from synapse.utils.module_loading import import_string
4
6
 
5
7
 
8
+ @register_action
6
9
  class TrainAction(Action):
7
- # TODO implement specifying which hardware to use (gpu-n, cpu)
10
+ name = 'train'
11
+ category = PluginCategory.NEURAL_NET
12
+ method = RunMethod.JOB
8
13
 
9
14
  def get_input_dataset_for_training(self, model_id=None):
10
15
  """
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class PostAnnotationAction(Action):
8
+ name = 'post_annotation'
9
+ category = PluginCategory.POST_ANNOTATION
10
+ method = RunMethod.TASK
@@ -0,0 +1,10 @@
1
+ from synapse.plugins.categories.base import Action
2
+ from synapse.plugins.categories.decorators import register_action
3
+ from synapse.plugins.enums import RunMethod, PluginCategory
4
+
5
+
6
+ @register_action
7
+ class PreAnnotationAction(Action):
8
+ name = 'pre_annotation'
9
+ category = PluginCategory.PRE_ANNOTATION
10
+ method = RunMethod.TASK
@@ -0,0 +1,16 @@
1
+ import pkgutil
2
+ from importlib import import_module
3
+
4
+ from synapse.plugins.enums import PluginCategory
5
+
6
+ _REGISTERED_ACTIONS = {}
7
+
8
+
9
+ def register_actions():
10
+ if not _REGISTERED_ACTIONS:
11
+ for category in PluginCategory:
12
+ plugin_category_module_name = f'synapse.plugins.categories.{category.value}.actions'
13
+ plugin_category_module = import_module(plugin_category_module_name)
14
+ for _, action_name, _ in pkgutil.iter_modules(plugin_category_module.__path__):
15
+ action_module_name = f'{plugin_category_module_name}.{action_name}'
16
+ import_module(action_module_name)
@@ -0,0 +1,16 @@
1
+ from enum import Enum
2
+
3
+
4
+ class RunMethod(Enum):
5
+ JOB = 'job'
6
+ TASK = 'task'
7
+ RESTAPI = 'restapi'
8
+
9
+
10
+ class PluginCategory(Enum):
11
+ NEURAL_NET = 'neural_net'
12
+ EXPORT = 'export'
13
+ IMPORT = 'import'
14
+ POST_ANNOTATION = 'post_annotation'
15
+ PRE_ANNOTATION = 'pre_annotation'
16
+ DATA_VALIDATION = 'data_validation'
@@ -0,0 +1,5 @@
1
+ class Job:
2
+ job_id = None
3
+
4
+ def __init__(self, job_id):
5
+ self.job_id = job_id
@@ -0,0 +1,79 @@
1
+ import os
2
+ import re
3
+ import subprocess
4
+ import tempfile
5
+ import hashlib
6
+ from pathlib import Path
7
+
8
+ import boto3
9
+
10
+
11
+ def calculate_checksum(file_path):
12
+ md5_hash = hashlib.md5()
13
+ with open(file_path, 'rb') as f:
14
+ for byte_block in iter(lambda: f.read(4096), b''):
15
+ md5_hash.update(byte_block)
16
+ checksum = md5_hash.hexdigest()
17
+ return f'dev-{checksum}'
18
+
19
+
20
+ def upload_to_s3(file_path, bucket_name, object_name, endpoint_url, access_key, secret_key):
21
+ s3_client = boto3.client(
22
+ 's3',
23
+ endpoint_url=endpoint_url,
24
+ aws_access_key_id=access_key,
25
+ aws_secret_access_key=secret_key,
26
+ )
27
+ s3_client.upload_file(file_path, bucket_name, object_name)
28
+
29
+
30
+ def upload_path(
31
+ source_path,
32
+ endpoint_url=None,
33
+ bucket_name=None,
34
+ access_key=None,
35
+ secret_key=None,
36
+ base_url=None,
37
+ ):
38
+ if not endpoint_url:
39
+ endpoint_url = os.environ['PLUGIN_UPLOAD_S3_ENDPOINT_URL']
40
+ if not bucket_name:
41
+ bucket_name = os.environ['PLUGIN_UPLOAD_S3_BUCKET_NAME']
42
+ if not access_key:
43
+ access_key = os.environ['PLUGIN_UPLOAD_S3_ACCESS_KEY']
44
+ if not secret_key:
45
+ secret_key = os.environ['PLUGIN_UPLOAD_S3_SECRET_KEY']
46
+ if not base_url:
47
+ base_url = os.environ['PLUGIN_UPLOAD_S3_BASE_URL']
48
+
49
+ with tempfile.TemporaryDirectory() as temp_dir:
50
+ temp_archive_path = os.path.join(temp_dir, 'archive.zip')
51
+ command = f'git ls-files --others --exclude-standard --cached | zip -q --names-stdin {temp_archive_path}'
52
+
53
+ subprocess.run(command, cwd=source_path, shell=True, check=True)
54
+
55
+ checksum = calculate_checksum(temp_archive_path)
56
+ # TODO subpath param으로 받기
57
+ s3_object_name = f'assets/{checksum}.zip'
58
+
59
+ upload_to_s3(temp_archive_path, bucket_name, s3_object_name, endpoint_url, access_key, secret_key)
60
+ return f'{base_url}/{bucket_name}/{s3_object_name}'
61
+
62
+
63
+ def change_whl_version(whl_name, new_version):
64
+ pattern = r'^(?P<distribution>.+?)-(?P<version>\d+(\.\d+)*)(?P<rest>-.+\.whl)$'
65
+ return re.sub(pattern, rf'\g<distribution>-{new_version}\g<rest>', whl_name)
66
+
67
+
68
+ def build_and_upload(source_path, endpoint_url, bucket_name, access_key, secret_key, base_url, virtualenv_path='.venv'):
69
+ # TODO 이미 빌드한 whl이 있으면 skip
70
+ subprocess.run(f'{virtualenv_path}/bin/python -m build --wheel', cwd=source_path, shell=True, check=True)
71
+
72
+ whl_file = next(Path(source_path, 'dist').glob('*.whl'), None)
73
+ checksum = calculate_checksum(whl_file)
74
+
75
+ # TODO subpath param으로 받기
76
+ s3_object_name = f'assets/{change_whl_version(whl_file.name, checksum)}'
77
+
78
+ upload_to_s3(str(whl_file), bucket_name, s3_object_name, endpoint_url, access_key, secret_key)
79
+ return f'{base_url}/{bucket_name}/{s3_object_name}'
@@ -0,0 +1,40 @@
1
+ import json
2
+
3
+ from synapse.plugins.categories.registry import _REGISTERED_ACTIONS, register_actions
4
+ from synapse.utils.file import get_dict_from_file
5
+ from synapse.utils.string import hash_text
6
+
7
+
8
+ def get_action(action, params_data, *args, **kwargs):
9
+ if isinstance(params_data, str):
10
+ try:
11
+ params = json.loads(params_data)
12
+ except json.JSONDecodeError:
13
+ params = get_dict_from_file(params_data)
14
+ else:
15
+ params = params_data
16
+
17
+ config_data = kwargs.pop('config', False)
18
+ if config_data:
19
+ if isinstance(config_data, str):
20
+ config = get_dict_from_file(config_data)
21
+ else:
22
+ config = config_data
23
+ else:
24
+ config = get_dict_from_file('config.yaml')
25
+ category = config['category']
26
+ return get_action_class(category, action)(params, config, *args, **kwargs)
27
+
28
+
29
+ def get_action_class(category, action):
30
+ register_actions()
31
+ return _REGISTERED_ACTIONS[category][action]
32
+
33
+
34
+ def get_available_actions(category):
35
+ register_actions()
36
+ return list(_REGISTERED_ACTIONS[category].keys())
37
+
38
+
39
+ def get_plugin_checksum(plugin_id):
40
+ return hash_text(plugin_id)
File without changes
@@ -0,0 +1,2 @@
1
+ def get_message():
2
+ return 'hello world from sdk'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synapse-sdk
3
- Version: 0.1.1a0
3
+ Version: 1.0.0a0
4
4
  Summary: synapse sdk
5
5
  Author-email: datamaker <developer@datamaker.io>
6
6
  License: MIT
@@ -8,8 +8,10 @@ Classifier: Programming Language :: Python :: 3
8
8
  Requires-Python: >=3.11
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
+ Requires-Dist: boto3
11
12
  Requires-Dist: requests
12
13
  Requires-Dist: tqdm
14
+ Requires-Dist: python-dotenv
13
15
  Requires-Dist: pyyaml
14
16
  Requires-Dist: pydantic
15
17
  Requires-Dist: ray[all]
@@ -18,21 +18,37 @@ synapse/client/mixins/dataset.py
18
18
  synapse/client/mixins/integration.py
19
19
  synapse/client/mixins/ml.py
20
20
  synapse/plugins/__init__.py
21
+ synapse/plugins/enums.py
22
+ synapse/plugins/job.py
23
+ synapse/plugins/upload.py
21
24
  synapse/plugins/utils.py
22
25
  synapse/plugins/categories/__init__.py
23
26
  synapse/plugins/categories/base.py
24
- synapse/plugins/categories/custom_script/__init__.py
25
- synapse/plugins/categories/custom_script/actions/__init__.py
27
+ synapse/plugins/categories/decorators.py
28
+ synapse/plugins/categories/registry.py
29
+ synapse/plugins/categories/data_validation/__init__.py
30
+ synapse/plugins/categories/data_validation/actions/__init__.py
31
+ synapse/plugins/categories/data_validation/actions/validation.py
26
32
  synapse/plugins/categories/export/__init__.py
27
33
  synapse/plugins/categories/export/actions/__init__.py
34
+ synapse/plugins/categories/export/actions/export.py
28
35
  synapse/plugins/categories/import/__init__.py
29
36
  synapse/plugins/categories/import/actions/__init__.py
37
+ synapse/plugins/categories/import/actions/import.py
30
38
  synapse/plugins/categories/neural_net/__init__.py
31
39
  synapse/plugins/categories/neural_net/actions/__init__.py
32
40
  synapse/plugins/categories/neural_net/actions/deployment.py
41
+ synapse/plugins/categories/neural_net/actions/inference.py
33
42
  synapse/plugins/categories/neural_net/actions/test.py
34
43
  synapse/plugins/categories/neural_net/actions/train.py
44
+ synapse/plugins/categories/post_annotation/__init__.py
45
+ synapse/plugins/categories/post_annotation/actions/__init__.py
46
+ synapse/plugins/categories/post_annotation/actions/post_annotation.py
47
+ synapse/plugins/categories/pre_annotation/__init__.py
48
+ synapse/plugins/categories/pre_annotation/actions/__init__.py
49
+ synapse/plugins/categories/pre_annotation/actions/pre_annotation.py
35
50
  synapse/utils/__init__.py
51
+ synapse/utils/debug.py
36
52
  synapse/utils/file.py
37
53
  synapse/utils/module_loading.py
38
54
  synapse/utils/string.py
@@ -1,5 +1,7 @@
1
+ boto3
1
2
  requests
2
3
  tqdm
4
+ python-dotenv
3
5
  pyyaml
4
6
  pydantic
5
7
  ray[all]
@@ -1,11 +0,0 @@
1
- from synapse.plugins.categories.neural_net.actions.deployment import DeploymentAction
2
- from synapse.plugins.categories.neural_net.actions.test import TestAction
3
- from synapse.plugins.categories.neural_net.actions.train import TrainAction
4
-
5
- ACTIONS = {
6
- 'neural_net': {
7
- 'deployment': DeploymentAction,
8
- 'train': TrainAction,
9
- 'test': TestAction,
10
- },
11
- }
@@ -1,49 +0,0 @@
1
- from functools import cached_property
2
-
3
- from synapse.loggers import ConsoleLogger
4
- from synapse.plugins.utils import get_plugin_checksum
5
-
6
-
7
- class Action:
8
- params = None
9
- config = None
10
- client = None
11
- logger = None
12
-
13
- def __init__(self, params, config):
14
- self.params = params
15
- self.config = config
16
-
17
- # TODO logger 지정 방식 개선
18
- self.logger = ConsoleLogger()
19
-
20
- @cached_property
21
- def plugin_id(self):
22
- code = self.config['code']
23
- version = self.config['version']
24
- return f'{code}@{version}'
25
-
26
- @cached_property
27
- def plugin_checksum(self):
28
- return get_plugin_checksum(self.plugin_id)
29
-
30
- def get_runtime_env(self):
31
- return {
32
- # TODO url기반 working_dir 가져오기
33
- 'working_dir': ''
34
- }
35
-
36
- def run(self):
37
- raise NotImplementedError
38
-
39
- def set_progress(self, current, total, category=''):
40
- self.logger.set_progress(current, total, category)
41
-
42
- def log(self, action, data):
43
- self.logger.log(action, data)
44
-
45
- def log_event(self, message):
46
- self.logger.log('event', {'content': message})
47
-
48
- def end_log(self):
49
- self.log_event('Plugin run is complete.')
@@ -1,24 +0,0 @@
1
- from ray import serve
2
-
3
- from synapse.plugins.categories.base import Action
4
- from synapse.utils.module_loading import import_string
5
-
6
-
7
- class DeploymentAction(Action):
8
- deployment = None
9
-
10
- def __init__(self, *args, **kwargs):
11
- super().__init__(*args, **kwargs)
12
- self.deployment = self.get_deployment()
13
-
14
- def get_deployment(self):
15
- entrypoint = self.config['actions']['deployment']['entrypoint']
16
- deployment = import_string(entrypoint)
17
- return serve.deployment(ray_actor_options=self.get_actor_options())(deployment)
18
-
19
- def get_actor_options(self):
20
- return {'runtime_env': self.get_runtime_env()}
21
-
22
- def run(self):
23
- serve.delete(self.plugin_id)
24
- serve.run(self.deployment.bind(), name=self.plugin_id, route_prefix=f'/{self.plugin_checksum}')
@@ -1,6 +0,0 @@
1
- from synapse.plugins.categories.base import Action
2
-
3
-
4
- class TestAction(Action):
5
- def run(self):
6
- pass
@@ -1,26 +0,0 @@
1
- import json
2
-
3
- from synapse.utils.file import get_dict_from_file
4
- from synapse.utils.string import hash_text
5
-
6
-
7
- def get_action(action, json_or_path):
8
- from synapse.plugins.categories import ACTIONS
9
-
10
- try:
11
- params = json.loads(json_or_path)
12
- except json.JSONDecodeError:
13
- params = get_dict_from_file(json_or_path)
14
- config = get_dict_from_file('config.yaml')
15
- category = config['category']
16
- return ACTIONS[category][action](params, config)
17
-
18
-
19
- def get_available_actions(category):
20
- from synapse.plugins.categories import ACTIONS
21
-
22
- return list(ACTIONS[category].keys())
23
-
24
-
25
- def get_plugin_checksum(plugin_id):
26
- return hash_text(plugin_id)
File without changes
File without changes
File without changes
File without changes