nvidia-nat-mysql 1.3.dev0__py3-none-any.whl → 1.3.0rc1__py3-none-any.whl

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.
@@ -14,7 +14,7 @@
14
14
  # limitations under the License.
15
15
 
16
16
  import logging
17
- import pickle
17
+ import re
18
18
 
19
19
  import aiomysql
20
20
  from aiomysql.pool import Pool
@@ -23,7 +23,6 @@ from nat.data_models.object_store import KeyAlreadyExistsError
23
23
  from nat.data_models.object_store import NoSuchKeyError
24
24
  from nat.object_store.interfaces import ObjectStore
25
25
  from nat.object_store.models import ObjectStoreItem
26
- from nat.plugins.mysql.object_store import MySQLObjectStoreClientConfig
27
26
  from nat.utils.type_utils import override
28
27
 
29
28
  logger = logging.getLogger(__name__)
@@ -34,66 +33,78 @@ class MySQLObjectStore(ObjectStore):
34
33
  Implementation of ObjectStore that stores objects in a MySQL database.
35
34
  """
36
35
 
37
- def __init__(self, config: MySQLObjectStoreClientConfig):
38
-
36
+ def __init__(self, *, bucket_name: str, host: str, port: int, username: str | None, password: str | None):
39
37
  super().__init__()
40
38
 
41
- self._config = config
39
+ if not re.fullmatch(r"[A-Za-z0-9_-]+", bucket_name):
40
+ raise ValueError("bucket_name must match [A-Za-z0-9_-]+")
41
+
42
+ self._bucket_name = bucket_name
43
+ self._host = host
44
+ self._port = port
45
+ self._username = username
46
+ self._password = password
47
+
42
48
  self._conn_pool: Pool | None = None
43
49
 
44
- self._schema = f"`bucket_{self._config.bucket_name}`"
50
+ @property
51
+ def _schema(self) -> str:
52
+ return f"`bucket_{self._bucket_name}`"
45
53
 
46
- async def __aenter__(self):
54
+ async def __aenter__(self) -> "MySQLObjectStore":
47
55
 
48
56
  if self._conn_pool is not None:
49
57
  raise RuntimeError("Connection already established")
50
58
 
51
59
  self._conn_pool = await aiomysql.create_pool(
52
- host=self._config.host,
53
- port=self._config.port,
54
- user=self._config.username,
55
- password=self._config.password,
60
+ host=self._host,
61
+ port=self._port,
62
+ user=self._username,
63
+ password=self._password,
56
64
  autocommit=False, # disable autocommit for transactions
57
65
  )
58
66
  assert self._conn_pool is not None
59
67
 
60
- logger.info(
61
- f"Created connection pool for {self._config.bucket_name} at {self._config.host}:{self._config.port}")
68
+ logger.info("Created connection pool for %s at %s:%s", self._bucket_name, self._host, self._port)
62
69
 
63
70
  async with self._conn_pool.acquire() as conn:
64
71
  async with conn.cursor() as cur:
65
72
 
66
- # Create schema (database) if doesn't exist
67
- await cur.execute(f"CREATE SCHEMA IF NOT EXISTS {self._schema} DEFAULT CHARACTER SET utf8mb4;")
68
- await cur.execute(f"USE {self._schema};")
73
+ # Suppress MySQL "IF NOT EXISTS" notes that surface as warnings in the driver
74
+ await cur.execute("SET sql_notes = 0;")
75
+ try:
76
+ # Create schema (database) if doesn't exist
77
+ await cur.execute(f"CREATE SCHEMA IF NOT EXISTS {self._schema} DEFAULT CHARACTER SET utf8mb4;")
78
+ await cur.execute(f"USE {self._schema};")
69
79
 
70
- # Create metadata table_schema
71
- await cur.execute("""
72
- CREATE TABLE IF NOT EXISTS object_meta (
73
- id INT AUTO_INCREMENT PRIMARY KEY,
74
- path VARCHAR(768) NOT NULL UNIQUE,
75
- size BIGINT NOT NULL,
76
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
77
- ) ENGINE=InnoDB;
78
- """)
79
-
80
- # Create blob data table
81
- await cur.execute("""
82
- CREATE TABLE IF NOT EXISTS object_data (
83
- id INT PRIMARY KEY,
84
- data LONGBLOB NOT NULL,
85
- FOREIGN KEY (id) REFERENCES object_meta(id) ON DELETE CASCADE
86
- ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
87
- """)
80
+ # Create metadata table_schema
81
+ await cur.execute("""
82
+ CREATE TABLE IF NOT EXISTS object_meta (
83
+ id INT AUTO_INCREMENT PRIMARY KEY,
84
+ path VARCHAR(768) NOT NULL UNIQUE,
85
+ size BIGINT NOT NULL,
86
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
87
+ ) ENGINE=InnoDB;
88
+ """)
89
+
90
+ # Create blob data table
91
+ await cur.execute("""
92
+ CREATE TABLE IF NOT EXISTS object_data (
93
+ id INT PRIMARY KEY,
94
+ data LONGBLOB NOT NULL,
95
+ FOREIGN KEY (id) REFERENCES object_meta(id) ON DELETE CASCADE
96
+ ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
97
+ """)
98
+ finally:
99
+ await cur.execute("SET sql_notes = 1;")
88
100
 
89
101
  await conn.commit()
90
102
 
91
- logger.info(
92
- f"Created schema and tables for {self._config.bucket_name} at {self._config.host}:{self._config.port}")
103
+ logger.info("Created schema and tables for %s at %s:%s", self._bucket_name, self._host, self._port)
93
104
 
94
105
  return self
95
106
 
96
- async def __aexit__(self, exc_type, exc_value, traceback):
107
+ async def __aexit__(self, exc_type, exc_value, traceback) -> None:
97
108
 
98
109
  if not self._conn_pool:
99
110
  raise RuntimeError("Connection not established")
@@ -120,11 +131,10 @@ class MySQLObjectStore(ObjectStore):
120
131
  (key, len(item.data)))
121
132
  if cur.rowcount == 0:
122
133
  raise KeyAlreadyExistsError(
123
- key=key, additional_message=f"MySQL table {self._config.bucket_name} already has key {key}")
134
+ key=key, additional_message=f"MySQL table {self._bucket_name} already has key {key}")
124
135
  await cur.execute("SELECT id FROM object_meta WHERE path=%s FOR UPDATE;", (key, ))
125
136
  (obj_id, ) = await cur.fetchone()
126
-
127
- blob = pickle.dumps(item)
137
+ blob = item.model_dump_json()
128
138
  await cur.execute("INSERT INTO object_data (id, data) VALUES (%s, %s)", (obj_id, blob))
129
139
  await conn.commit()
130
140
  except Exception:
@@ -145,13 +155,13 @@ class MySQLObjectStore(ObjectStore):
145
155
  await cur.execute(
146
156
  """
147
157
  INSERT INTO object_meta (path, size)
148
- VALUES (%s, %s)
149
- ON DUPLICATE KEY UPDATE size=VALUES(size), created_at=CURRENT_TIMESTAMP
158
+ VALUES (%s, %s) AS new
159
+ ON DUPLICATE KEY UPDATE size=new.size, created_at=CURRENT_TIMESTAMP
150
160
  """, (key, len(item.data)))
151
161
  await cur.execute("SELECT id FROM object_meta WHERE path=%s FOR UPDATE;", (key, ))
152
162
  (obj_id, ) = await cur.fetchone()
153
163
 
154
- blob = pickle.dumps(item)
164
+ blob = item.model_dump_json()
155
165
  await cur.execute("REPLACE INTO object_data (id, data) VALUES (%s, %s)", (obj_id, blob))
156
166
  await conn.commit()
157
167
  except Exception:
@@ -176,9 +186,9 @@ class MySQLObjectStore(ObjectStore):
176
186
  """, (key, ))
177
187
  row = await cur.fetchone()
178
188
  if not row:
179
- raise NoSuchKeyError(
180
- key=key, additional_message=f"MySQL table {self._config.bucket_name} does not have key {key}")
181
- return pickle.loads(row[0])
189
+ raise NoSuchKeyError(key=key,
190
+ additional_message=f"MySQL table {self._bucket_name} does not have key {key}")
191
+ return ObjectStoreItem.model_validate_json(row[0].decode("utf-8"))
182
192
 
183
193
  @override
184
194
  async def delete_object(self, key: str):
@@ -200,8 +210,7 @@ class MySQLObjectStore(ObjectStore):
200
210
 
201
211
  if cur.rowcount == 0:
202
212
  raise NoSuchKeyError(
203
- key=key,
204
- additional_message=f"MySQL table {self._config.bucket_name} does not have key {key}")
213
+ key=key, additional_message=f"MySQL table {self._bucket_name} does not have key {key}")
205
214
 
206
215
  await conn.commit()
207
216
  except Exception:
@@ -58,9 +58,9 @@ class MySQLObjectStoreClientConfig(ObjectStoreBaseConfig, name="mysql"):
58
58
 
59
59
 
60
60
  @register_object_store(config_type=MySQLObjectStoreClientConfig)
61
- async def mysql_object_store_client(config: MySQLObjectStoreClientConfig, builder: Builder):
61
+ async def mysql_object_store_client(config: MySQLObjectStoreClientConfig, _builder: Builder):
62
62
 
63
63
  from .mysql_object_store import MySQLObjectStore
64
64
 
65
- async with MySQLObjectStore(config) as store:
65
+ async with MySQLObjectStore(**config.model_dump(exclude={"type"}, exclude_none=True)) as store:
66
66
  yield store
@@ -13,7 +13,6 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
- # pylint: disable=unused-import
17
16
  # flake8: noqa
18
17
  # isort:skip_file
19
18
 
@@ -1,10 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-nat-mysql
3
- Version: 1.3.dev0
3
+ Version: 1.3.0rc1
4
4
  Summary: Subpackage for MySQL integration in NeMo Agent toolkit
5
5
  Keywords: ai,agents,memory,data store
6
6
  Classifier: Programming Language :: Python
7
- Requires-Python: >=3.12
7
+ Classifier: Programming Language :: Python :: 3.11
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Programming Language :: Python :: 3.13
10
+ Requires-Python: <3.14,>=3.11
8
11
  Description-Content-Type: text/markdown
9
- Requires-Dist: nvidia-nat==v1.3-dev
12
+ Requires-Dist: nvidia-nat==v1.3.0-rc1
10
13
  Requires-Dist: aiomysql>=0.2.0
@@ -0,0 +1,9 @@
1
+ nat/plugins/mysql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ nat/plugins/mysql/mysql_object_store.py,sha256=OhOOCXMBcEBITfTt1mqpCAcDUgwIc0_HzkcTKO1Kezc,8602
3
+ nat/plugins/mysql/object_store.py,sha256=iEkWrlooEXqAfJYdg39cKe9EMCvQJ6CqCeeoL_cmOrw,2651
4
+ nat/plugins/mysql/register.py,sha256=iBGq69m0rbZ3BTisA4Lt5UCHtW0Pc7m-l8G8dz-_pBc,813
5
+ nvidia_nat_mysql-1.3.0rc1.dist-info/METADATA,sha256=g9STcuk1JaCUmdhgrWO1epoJ89NQ5DjAXEzgsV3JwaQ,500
6
+ nvidia_nat_mysql-1.3.0rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ nvidia_nat_mysql-1.3.0rc1.dist-info/entry_points.txt,sha256=ZI7ielmDX-k_OPXGvpRB5tKFVR5kMCHmHGwLWqxRKh0,56
8
+ nvidia_nat_mysql-1.3.0rc1.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
9
+ nvidia_nat_mysql-1.3.0rc1.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- nat/plugins/mysql/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- nat/plugins/mysql/mysql_object_store.py,sha256=EXHuA6z28__lH6qhSyGuIPWLPZ-5BzH9EHVCkpDYyvE,8042
3
- nat/plugins/mysql/object_store.py,sha256=IWMJFKBhn0lH7UGHuYkYht82TwIe5KXS7VUhQrlNRyI,2600
4
- nat/plugins/mysql/register.py,sha256=7gqnwyDrYttIlEaa7lo9AASYt-2GrZJE0YT2jpKjepo,845
5
- nvidia_nat_mysql-1.3.dev0.dist-info/METADATA,sha256=g11nXToNcwBEvbspx29N-29LrI_sGnp3Z0h2z2Wh7XI,339
6
- nvidia_nat_mysql-1.3.dev0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
- nvidia_nat_mysql-1.3.dev0.dist-info/entry_points.txt,sha256=ZI7ielmDX-k_OPXGvpRB5tKFVR5kMCHmHGwLWqxRKh0,56
8
- nvidia_nat_mysql-1.3.dev0.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
9
- nvidia_nat_mysql-1.3.dev0.dist-info/RECORD,,