Skip to content

Commit 5656a77

Browse files
authored
Merge pull request #230 Merge main into v3
2 parents cda5dad + 876d1f0 commit 5656a77

File tree

10 files changed

+92
-19
lines changed

10 files changed

+92
-19
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
## 3.0.1b1 ##
3636
* start 3.0 beta branch
3737

38+
## 2.13.4 ##
39+
* fixed sqlalchemy get_columns method with not null columns
40+
3841
## 2.13.3 ##
3942
* fixed use transaction object when commit with flag
4043

examples/_sqlalchemy_example/example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def run_example_core(engine):
196196
def main():
197197
parser = argparse.ArgumentParser(
198198
formatter_class=argparse.RawDescriptionHelpFormatter,
199-
description="""\033[92mYandex.Database examples sqlalchemy usage.\x1b[0m\n""",
199+
description="""\033[92mYandex.Database examples _sqlalchemy usage.\x1b[0m\n""",
200200
)
201201
parser.add_argument(
202202
"-d",
@@ -219,7 +219,7 @@ def main():
219219
)
220220

221221
logging.basicConfig(level=logging.INFO)
222-
logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO)
222+
logging.getLogger("_sqlalchemy.engine").setLevel(logging.INFO)
223223

224224
run_example_core(engine)
225225
# run_example_orm(engine)

tests/_sqlalchemy/conftest.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
import sqlalchemy as sa
3+
4+
from ydb._sqlalchemy import register_dialect
5+
6+
7+
@pytest.fixture(scope="module")
8+
def engine(endpoint, database):
9+
register_dialect()
10+
engine = sa.create_engine(
11+
"yql:///ydb/",
12+
connect_args={"database": database, "endpoint": endpoint},
13+
)
14+
15+
yield engine
16+
engine.dispose()
17+
18+
19+
@pytest.fixture(scope="module")
20+
def connection(engine):
21+
with engine.connect() as conn:
22+
yield conn
File renamed without changes.

tests/sqlalchemy/conftest.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import pytest
22
import sqlalchemy as sa
33

4-
from ydb._sqlalchemy import register_dialect
4+
from ydb.sqlalchemy import register_dialect
55

66

7-
@pytest.fixture(scope="module")
8-
def engine(endpoint, database):
7+
@pytest.fixture
8+
def sa_engine(endpoint, database):
99
register_dialect()
1010
engine = sa.create_engine(
1111
"yql:///ydb/",
@@ -14,9 +14,3 @@ def engine(endpoint, database):
1414

1515
yield engine
1616
engine.dispose()
17-
18-
19-
@pytest.fixture(scope="module")
20-
def connection(engine):
21-
with engine.connect() as conn:
22-
yield conn

tests/sqlalchemy/test_inspect.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import ydb
2+
3+
import sqlalchemy as sa
4+
5+
6+
def test_get_columns(driver_sync, sa_engine):
7+
session = ydb.retry_operation_sync(
8+
lambda: driver_sync.table_client.session().create()
9+
)
10+
session.execute_scheme(
11+
"CREATE TABLE test(id Int64 NOT NULL, value TEXT, num DECIMAL(22, 9), PRIMARY KEY (id))"
12+
)
13+
inspect = sa.inspect(sa_engine)
14+
columns = inspect.get_columns("test")
15+
for c in columns:
16+
c["type"] = type(c["type"])
17+
18+
assert columns == [
19+
{"name": "id", "type": sa.INTEGER, "nullable": False},
20+
{"name": "value", "type": sa.TEXT, "nullable": True},
21+
{"name": "num", "type": sa.DECIMAL, "nullable": True},
22+
]
23+
24+
session.execute_scheme("DROP TABLE test")

tests/test_errors.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import ydb
2+
import pytest
3+
4+
from os import path
5+
6+
7+
def test_scheme_error(driver_sync, database):
8+
session = driver_sync.table_client.session().create()
9+
with pytest.raises(ydb.issues.SchemeError) as exc:
10+
session.drop_table(path.join(database, "foobartable"))
11+
12+
server_code = ydb.issues.StatusCode.SCHEME_ERROR
13+
14+
assert type(exc.value) == ydb.issues.SchemeError
15+
assert exc.value.status == server_code
16+
assert f"server_code: {server_code}" in str(exc.value)
17+
assert "Path does not exist" in str(exc.value)

ydb/issues.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,18 @@ class SessionPoolEmpty(Error, queue.Empty):
159159
def _format_issues(issues):
160160
if not issues:
161161
return ""
162+
162163
return " ,".join(
163-
[text_format.MessageToString(issue, False, True) for issue in issues]
164+
text_format.MessageToString(issue, as_utf8=False, as_one_line=True)
165+
for issue in issues
164166
)
165167

166168

169+
def _format_response(response):
170+
fmt_issues = _format_issues(response.issues)
171+
return f"{fmt_issues} (server_code: {response.status})"
172+
173+
167174
_success_status_codes = {StatusCode.STATUS_CODE_UNSPECIFIED, StatusCode.SUCCESS}
168175
_server_side_error_map = {
169176
StatusCode.BAD_REQUEST: BadRequest,
@@ -190,4 +197,4 @@ def _format_issues(issues):
190197
def _process_response(response_proto):
191198
if response_proto.status not in _success_status_codes:
192199
exc_obj = _server_side_error_map.get(response_proto.status)
193-
raise exc_obj(_format_issues(response_proto.issues), response_proto.issues)
200+
raise exc_obj(_format_response(response_proto), response_proto.issues)

ydb/sqlalchemy/__init__.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,16 @@ def visit_function(self, func, add_to_result_map=None, **kwargs):
191191
ydb.PrimitiveType.DyNumber: sa.TEXT,
192192
}
193193

194-
def _get_column_type(t):
195-
if isinstance(t.item, ydb.DecimalType):
196-
return sa.DECIMAL(precision=t.item.precision, scale=t.item.scale)
194+
def _get_column_info(t):
195+
nullable = False
196+
if isinstance(t, ydb.OptionalType):
197+
nullable = True
198+
t = t.item
197199

198-
return COLUMN_TYPES[t.item]
200+
if isinstance(t, ydb.DecimalType):
201+
return sa.DECIMAL(precision=t.precision, scale=t.scale), nullable
202+
203+
return COLUMN_TYPES[t], nullable
199204

200205
class YqlDialect(DefaultDialect):
201206
name = "yql"
@@ -250,11 +255,12 @@ def get_columns(self, connection, table_name, schema=None, **kw):
250255
columns = raw_conn.describe(qt)
251256
as_compatible = []
252257
for column in columns:
258+
col_type, nullable = _get_column_info(column.type)
253259
as_compatible.append(
254260
{
255261
"name": column.name,
256-
"type": _get_column_type(column.type),
257-
"nullable": True,
262+
"type": col_type,
263+
"nullable": nullable,
258264
}
259265
)
260266

0 commit comments

Comments
 (0)