learnml-sdk 0.1.0__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.
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: learnml-sdk
3
+ Version: 0.1.0
4
+ Summary: Python SDK for the LearnML training data management platform
5
+ Home-page: https://github.com/milindjain0/learnml
6
+ Author: LearnML
7
+ Author-email: milindjain0@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: grpcio>=1.50.0
14
+ Requires-Dist: protobuf>=4.0.0
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ # LearnML — ML Data Management System
26
+
27
+ A unified platform for storing ML training data (traditional labeled data + LLM training data), model checkpoints, and training metrics.
28
+
29
+ **Stack:** C++17 · gRPC · Protocol Buffers · PostgreSQL · Grafana
30
+
31
+ ---
32
+
33
+ ## Quick Start
34
+
35
+ ### Prerequisites
36
+
37
+ - Docker & Docker Compose
38
+ - CMake 3.20+
39
+ - C++17 compiler (GCC 9+ or Clang 10+)
40
+ - System packages: `grpc`, `protobuf`, `libpqxx`, `openssl`
41
+
42
+ ### 1. Start PostgreSQL & Grafana
43
+
44
+ ```bash
45
+ docker-compose up -d
46
+ ```
47
+
48
+ This starts:
49
+ - **PostgreSQL 16** on `localhost:5432` (auto-runs migrations)
50
+ - **Grafana 10** on `http://localhost:3000` (admin/admin)
51
+
52
+ ### 2. Build the Server
53
+
54
+ ```bash
55
+ mkdir build && cd build
56
+ cmake .. -DCMAKE_BUILD_TYPE=Release
57
+ make -j$(nproc)
58
+ ```
59
+
60
+ ### 3. Run the Server
61
+
62
+ ```bash
63
+ ./build/learnml_server ../config.json
64
+ ```
65
+
66
+ Server starts on `0.0.0.0:50051` by default.
67
+
68
+ ### 4. Test with grpcurl
69
+
70
+ ```bash
71
+ # Register a user
72
+ grpcurl -plaintext -d '{"email":"alice@test.com","password":"secret123","display_name":"Alice"}' \
73
+ localhost:50051 learnml.AuthService/Register
74
+
75
+ # Login
76
+ grpcurl -plaintext -d '{"email":"alice@test.com","password":"secret123"}' \
77
+ localhost:50051 learnml.AuthService/Login
78
+ # → Returns access_token and refresh_token
79
+
80
+ # Create a universe (use the access_token from login)
81
+ grpcurl -plaintext \
82
+ -H "Authorization: Bearer <access_token>" \
83
+ -d '{"name":"my-ml-project","description":"My first ML project"}' \
84
+ localhost:50051 learnml.UniverseService/CreateUniverse
85
+
86
+ # Create a data point
87
+ grpcurl -plaintext \
88
+ -H "Authorization: Bearer <token>" \
89
+ -H "x-universe-id: <universe_id>" \
90
+ -d '{"universe_id":"<id>","name":"sample_image","data_type":"IMAGE"}' \
91
+ localhost:50051 learnml.DataService/CreateDataPoint
92
+
93
+ # Create a training run and log metrics
94
+ grpcurl -plaintext \
95
+ -H "Authorization: Bearer <token>" \
96
+ -d '{"universe_id":"<id>","name":"gpt2-finetune","model_name":"gpt2"}' \
97
+ localhost:50051 learnml.MetricsService/CreateTrainingRun
98
+
99
+ grpcurl -plaintext \
100
+ -H "Authorization: Bearer <token>" \
101
+ -d '{"universe_id":"<id>","run_id":"<run_id>","snapshot":{"step":100,"metrics":{"loss":0.5,"perplexity":12.3}}}' \
102
+ localhost:50051 learnml.MetricsService/LogMetrics
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Architecture
108
+
109
+ ```
110
+ ┌──────────────┐ ┌──────────┐ ┌─────────┐
111
+ │ CLI / SDK │ │ React UI │ │ Grafana │
112
+ └──────┬───────┘ └────┬─────┘ └────┬────┘
113
+ │ │ │ (PostgreSQL datasource)
114
+ └───────┬───────┘ │
115
+ ▼ │
116
+ ┌──────────────────┐ │
117
+ │ Auth Interceptor│ │
118
+ │ (JWT validation)│ │
119
+ └────────┬─────────┘ │
120
+ ▼ │
121
+ ┌──────────────────┐ │
122
+ │ gRPC Services │ │
123
+ │ ┌─ Auth │ │
124
+ │ ├─ Universe │ │
125
+ │ ├─ Data │ │
126
+ │ ├─ Collection │ │
127
+ │ ├─ Checkpoint │ │
128
+ │ └─ Metrics │ │
129
+ └────────┬─────────┘ │
130
+ ▼ ▼
131
+ ┌──────────────────┐ ┌──────────────────┐
132
+ │ PostgreSQL │ │ File System │
133
+ │ (metadata + │ │ (blobs per │
134
+ │ RLS policies) │ │ universe) │
135
+ └──────────────────┘ └──────────────────┘
136
+ ```
137
+
138
+ ## Key Concepts
139
+
140
+ ### Universe
141
+ The top-level isolation boundary. All data is scoped to a universe. Users are granted **READ**, **WRITE**, or **ADMIN** access.
142
+
143
+ ### Data Points
144
+ Support traditional labeled data (image, video, PDF, text) and LLM training data (SFT, RL, pretraining).
145
+
146
+ ### Collections
147
+ Logical groups of data points. A data point can belong to multiple collections (many-to-many).
148
+
149
+ ### Checkpoints
150
+ Model checkpoint files with streaming upload/download APIs.
151
+
152
+ ### Training Metrics
153
+ Logged per-step with batch or streaming APIs. Grafana queries PostgreSQL directly.
154
+
155
+ ---
156
+
157
+ ## Configuration
158
+
159
+ Edit `config.json` or use environment variables:
160
+
161
+ | JSON Key | Env Variable | Default | Description |
162
+ |----------|-------------|---------|-------------|
163
+ | `server_address` | `LEARNML_SERVER_ADDRESS` | `0.0.0.0:50051` | gRPC listen address |
164
+ | `db_host` | `LEARNML_DB_HOST` | `localhost` | PostgreSQL host |
165
+ | `db_port` | `LEARNML_DB_PORT` | `5432` | PostgreSQL port |
166
+ | `db_name` | `LEARNML_DB_NAME` | `learnml` | Database name |
167
+ | `jwt_secret` | `LEARNML_JWT_SECRET` | dev secret | JWT signing key |
168
+ | `storage_root` | `LEARNML_STORAGE_ROOT` | `/tmp/learnml_storage` | File storage root |
169
+
170
+ ---
171
+
172
+ ## Project Structure
173
+
174
+ ```
175
+ learnml/
176
+ ├── proto/learnml/ # Protobuf schemas (7 files)
177
+ ├── src/
178
+ │ ├── auth/ # JWT, password hashing, gRPC interceptor
179
+ │ ├── db/ # Connection pool, repository, migrations
180
+ │ ├── services/ # 6 gRPC service implementations
181
+ │ ├── server/ # gRPC server + main entry point
182
+ │ └── util/ # Config, file store
183
+ ├── grafana/ # Dashboard JSON + provisioning
184
+ ├── CMakeLists.txt
185
+ ├── docker-compose.yml
186
+ ├── config.json
187
+ └── README.md
188
+ ```
189
+
190
+ ## License
191
+
192
+ MIT
@@ -0,0 +1,4 @@
1
+ from .client import LearnMLClient
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["LearnMLClient"]
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: learnml/auth.proto
5
+ # Protobuf Python Version: 6.31.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 31,
16
+ 1,
17
+ '',
18
+ 'learnml/auth.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
26
+
27
+
28
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12learnml/auth.proto\x12\x07learnml\x1a\x1fgoogle/protobuf/timestamp.proto\"g\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05\x65mail\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\x12.\n\ncreated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"H\n\x0fRegisterRequest\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x03 \x01(\t\"/\n\x10RegisterResponse\x12\x1b\n\x04user\x18\x01 \x01(\x0b\x32\r.learnml.User\"/\n\x0cLoginRequest\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12\x10\n\x08password\x18\x02 \x01(\t\"Y\n\rLoginResponse\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x15\n\rrefresh_token\x18\x02 \x01(\t\x12\x1b\n\x04user\x18\x03 \x01(\x0b\x32\r.learnml.User\",\n\x13RefreshTokenRequest\x12\x15\n\rrefresh_token\x18\x01 \x01(\t\"C\n\x14RefreshTokenResponse\x12\x14\n\x0c\x61\x63\x63\x65ss_token\x18\x01 \x01(\t\x12\x15\n\rrefresh_token\x18\x02 \x01(\t\"\x17\n\x15GetCurrentUserRequest\"5\n\x16GetCurrentUserResponse\x12\x1b\n\x04user\x18\x01 \x01(\x0b\x32\r.learnml.UserB\x03\xf8\x01\x01\x62\x06proto3')
29
+
30
+ _globals = globals()
31
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
32
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'learnml.auth_pb2', _globals)
33
+ if not _descriptor._USE_C_DESCRIPTORS:
34
+ _globals['DESCRIPTOR']._loaded_options = None
35
+ _globals['DESCRIPTOR']._serialized_options = b'\370\001\001'
36
+ _globals['_USER']._serialized_start=64
37
+ _globals['_USER']._serialized_end=167
38
+ _globals['_REGISTERREQUEST']._serialized_start=169
39
+ _globals['_REGISTERREQUEST']._serialized_end=241
40
+ _globals['_REGISTERRESPONSE']._serialized_start=243
41
+ _globals['_REGISTERRESPONSE']._serialized_end=290
42
+ _globals['_LOGINREQUEST']._serialized_start=292
43
+ _globals['_LOGINREQUEST']._serialized_end=339
44
+ _globals['_LOGINRESPONSE']._serialized_start=341
45
+ _globals['_LOGINRESPONSE']._serialized_end=430
46
+ _globals['_REFRESHTOKENREQUEST']._serialized_start=432
47
+ _globals['_REFRESHTOKENREQUEST']._serialized_end=476
48
+ _globals['_REFRESHTOKENRESPONSE']._serialized_start=478
49
+ _globals['_REFRESHTOKENRESPONSE']._serialized_end=545
50
+ _globals['_GETCURRENTUSERREQUEST']._serialized_start=547
51
+ _globals['_GETCURRENTUSERREQUEST']._serialized_end=570
52
+ _globals['_GETCURRENTUSERRESPONSE']._serialized_start=572
53
+ _globals['_GETCURRENTUSERRESPONSE']._serialized_end=625
54
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,24 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+ import warnings
5
+
6
+
7
+ GRPC_GENERATED_VERSION = '1.78.0'
8
+ GRPC_VERSION = grpc.__version__
9
+ _version_not_supported = False
10
+
11
+ try:
12
+ from grpc._utilities import first_version_is_lower
13
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
14
+ except ImportError:
15
+ _version_not_supported = True
16
+
17
+ if _version_not_supported:
18
+ raise RuntimeError(
19
+ f'The grpc package installed is at version {GRPC_VERSION},'
20
+ + ' but the generated code in learnml/auth_pb2_grpc.py depends on'
21
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
22
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
23
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
24
+ )
@@ -0,0 +1,71 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: learnml/checkpoint.proto
5
+ # Protobuf Python Version: 6.31.1
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 31,
16
+ 1,
17
+ '',
18
+ 'learnml/checkpoint.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
26
+ from learnml import common_pb2 as learnml_dot_common__pb2
27
+
28
+
29
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18learnml/checkpoint.proto\x12\x07learnml\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x14learnml/common.proto\"\xd1\x02\n\x0fModelCheckpoint\x12\n\n\x02id\x18\x01 \x01(\t\x12\x13\n\x0buniverse_id\x18\x02 \x01(\t\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x0c\n\x04step\x18\x04 \x01(\x03\x12\r\n\x05\x65poch\x18\x05 \x01(\x05\x12\x11\n\tfile_path\x18\x06 \x01(\t\x12\x17\n\x0f\x66ile_size_bytes\x18\x07 \x01(\x03\x12)\n\x06\x66ormat\x18\x08 \x01(\x0e\x32\x19.learnml.CheckpointFormat\x12\x38\n\x08metadata\x18\t \x03(\x0b\x32&.learnml.ModelCheckpoint.MetadataEntry\x12.\n\ncreated_at\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"h\n\x15SaveCheckpointRequest\x12\x33\n\x08metadata\x18\x01 \x01(\x0b\x32\x1f.learnml.SaveCheckpointMetadataH\x00\x12\x0f\n\x05\x63hunk\x18\x02 \x01(\x0cH\x00\x42\t\n\x07payload\"\x89\x02\n\x16SaveCheckpointMetadata\x12\x13\n\x0buniverse_id\x18\x01 \x01(\t\x12\x0e\n\x06run_id\x18\x02 \x01(\t\x12\x0c\n\x04step\x18\x03 \x01(\x03\x12\r\n\x05\x65poch\x18\x04 \x01(\x05\x12)\n\x06\x66ormat\x18\x05 \x01(\x0e\x32\x19.learnml.CheckpointFormat\x12?\n\x08metadata\x18\x06 \x03(\x0b\x32-.learnml.SaveCheckpointMetadata.MetadataEntry\x12\x10\n\x08\x66ilename\x18\x07 \x01(\t\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"F\n\x16SaveCheckpointResponse\x12,\n\ncheckpoint\x18\x01 \x01(\x0b\x32\x18.learnml.ModelCheckpoint\"C\n\x15LoadCheckpointRequest\x12\x13\n\x0buniverse_id\x18\x01 \x01(\t\x12\x15\n\rcheckpoint_id\x18\x02 \x01(\t\"_\n\x13LoadCheckpointChunk\x12,\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.learnml.ModelCheckpointH\x00\x12\x0f\n\x05\x63hunk\x18\x02 \x01(\x0cH\x00\x42\t\n\x07payload\"m\n\x16ListCheckpointsRequest\x12\x13\n\x0buniverse_id\x18\x01 \x01(\t\x12\x0e\n\x06run_id\x18\x02 \x01(\t\x12.\n\npagination\x18\x03 \x01(\x0b\x32\x1a.learnml.PaginationRequest\"y\n\x17ListCheckpointsResponse\x12-\n\x0b\x63heckpoints\x18\x01 \x03(\x0b\x32\x18.learnml.ModelCheckpoint\x12/\n\npagination\x18\x02 \x01(\x0b\x32\x1b.learnml.PaginationResponse\"A\n\x1aGetLatestCheckpointRequest\x12\x13\n\x0buniverse_id\x18\x01 \x01(\t\x12\x0e\n\x06run_id\x18\x02 \x01(\t\"K\n\x1bGetLatestCheckpointResponse\x12,\n\ncheckpoint\x18\x01 \x01(\x0b\x32\x18.learnml.ModelCheckpoint\"E\n\x17\x44\x65leteCheckpointRequest\x12\x13\n\x0buniverse_id\x18\x01 \x01(\t\x12\x15\n\rcheckpoint_id\x18\x02 \x01(\t\"\x1a\n\x18\x44\x65leteCheckpointResponse*\xd3\x01\n\x10\x43heckpointFormat\x12!\n\x1d\x43HECKPOINT_FORMAT_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x43HECKPOINT_FORMAT_PYTORCH\x10\x01\x12 \n\x1c\x43HECKPOINT_FORMAT_TENSORFLOW\x10\x02\x12\x1a\n\x16\x43HECKPOINT_FORMAT_ONNX\x10\x03\x12!\n\x1d\x43HECKPOINT_FORMAT_SAFETENSORS\x10\x04\x12\x1c\n\x18\x43HECKPOINT_FORMAT_CUSTOM\x10\x05\x42\x03\xf8\x01\x01\x62\x06proto3')
30
+
31
+ _globals = globals()
32
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
33
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'learnml.checkpoint_pb2', _globals)
34
+ if not _descriptor._USE_C_DESCRIPTORS:
35
+ _globals['DESCRIPTOR']._loaded_options = None
36
+ _globals['DESCRIPTOR']._serialized_options = b'\370\001\001'
37
+ _globals['_MODELCHECKPOINT_METADATAENTRY']._loaded_options = None
38
+ _globals['_MODELCHECKPOINT_METADATAENTRY']._serialized_options = b'8\001'
39
+ _globals['_SAVECHECKPOINTMETADATA_METADATAENTRY']._loaded_options = None
40
+ _globals['_SAVECHECKPOINTMETADATA_METADATAENTRY']._serialized_options = b'8\001'
41
+ _globals['_CHECKPOINTFORMAT']._serialized_start=1522
42
+ _globals['_CHECKPOINTFORMAT']._serialized_end=1733
43
+ _globals['_MODELCHECKPOINT']._serialized_start=93
44
+ _globals['_MODELCHECKPOINT']._serialized_end=430
45
+ _globals['_MODELCHECKPOINT_METADATAENTRY']._serialized_start=383
46
+ _globals['_MODELCHECKPOINT_METADATAENTRY']._serialized_end=430
47
+ _globals['_SAVECHECKPOINTREQUEST']._serialized_start=432
48
+ _globals['_SAVECHECKPOINTREQUEST']._serialized_end=536
49
+ _globals['_SAVECHECKPOINTMETADATA']._serialized_start=539
50
+ _globals['_SAVECHECKPOINTMETADATA']._serialized_end=804
51
+ _globals['_SAVECHECKPOINTMETADATA_METADATAENTRY']._serialized_start=383
52
+ _globals['_SAVECHECKPOINTMETADATA_METADATAENTRY']._serialized_end=430
53
+ _globals['_SAVECHECKPOINTRESPONSE']._serialized_start=806
54
+ _globals['_SAVECHECKPOINTRESPONSE']._serialized_end=876
55
+ _globals['_LOADCHECKPOINTREQUEST']._serialized_start=878
56
+ _globals['_LOADCHECKPOINTREQUEST']._serialized_end=945
57
+ _globals['_LOADCHECKPOINTCHUNK']._serialized_start=947
58
+ _globals['_LOADCHECKPOINTCHUNK']._serialized_end=1042
59
+ _globals['_LISTCHECKPOINTSREQUEST']._serialized_start=1044
60
+ _globals['_LISTCHECKPOINTSREQUEST']._serialized_end=1153
61
+ _globals['_LISTCHECKPOINTSRESPONSE']._serialized_start=1155
62
+ _globals['_LISTCHECKPOINTSRESPONSE']._serialized_end=1276
63
+ _globals['_GETLATESTCHECKPOINTREQUEST']._serialized_start=1278
64
+ _globals['_GETLATESTCHECKPOINTREQUEST']._serialized_end=1343
65
+ _globals['_GETLATESTCHECKPOINTRESPONSE']._serialized_start=1345
66
+ _globals['_GETLATESTCHECKPOINTRESPONSE']._serialized_end=1420
67
+ _globals['_DELETECHECKPOINTREQUEST']._serialized_start=1422
68
+ _globals['_DELETECHECKPOINTREQUEST']._serialized_end=1491
69
+ _globals['_DELETECHECKPOINTRESPONSE']._serialized_start=1493
70
+ _globals['_DELETECHECKPOINTRESPONSE']._serialized_end=1519
71
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,24 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+ import warnings
5
+
6
+
7
+ GRPC_GENERATED_VERSION = '1.78.0'
8
+ GRPC_VERSION = grpc.__version__
9
+ _version_not_supported = False
10
+
11
+ try:
12
+ from grpc._utilities import first_version_is_lower
13
+ _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
14
+ except ImportError:
15
+ _version_not_supported = True
16
+
17
+ if _version_not_supported:
18
+ raise RuntimeError(
19
+ f'The grpc package installed is at version {GRPC_VERSION},'
20
+ + ' but the generated code in learnml/checkpoint_pb2_grpc.py depends on'
21
+ + f' grpcio>={GRPC_GENERATED_VERSION}.'
22
+ + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
23
+ + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
24
+ )