Open NickCrews opened 3 hours ago
Definitely sounds like a bug to me! I would imagine the fix would be hereabouts https://github.com/Mause/duckdb_engine/blob/main/duckdb_engine/datatypes.py#L230 though can't say for certain without the stack trace
Ah, I think I have a fix. PR incoming!
@Mause I think that linked PR should be a pretty straightforward review. Thanks!
What happened?
Not sure if this is a bug, or I am using something wrong.
In what I'm sure is a very rare use case, if you have a type of
struct<..., array<struct>, ...>
, then I getTypeError: visit_struct() missing 1 required positional argument: 'identifier_preparer'
. I'm happy to submit a PR if you give me a pointer on where to go. Thank you!repro:
Details
```python-traceback --------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[1], line 35 15 contact_info: Mapped[dict | None] = mapped_column( 16 sadt.Struct( 17 { (...) 30 ) 31 ) 34 eng = sa.create_engine(\"duckdb:///:memory:\") ---> 35 Person.metadata.create_all(eng) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/schema.py:5868, in MetaData.create_all(self, bind, tables, checkfirst) 5844 def create_all( 5845 self, 5846 bind: _CreateDropBind, 5847 tables: Optional[_typing_Sequence[Table]] = None, 5848 checkfirst: bool = True, 5849 ) -> None: 5850 \"\"\"Create all tables stored in this metadata. 5851 5852 Conditional by default, will not attempt to recreate tables already (...) 5866 5867 \"\"\" -> 5868 bind._run_ddl_visitor( 5869 ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables 5870 ) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:3253, in Engine._run_ddl_visitor(self, visitorcallable, element, **kwargs) 3246 def _run_ddl_visitor( 3247 self, 3248 visitorcallable: Type[Union[SchemaGenerator, SchemaDropper]], 3249 element: SchemaItem, 3250 **kwargs: Any, 3251 ) -> None: 3252 with self.begin() as conn: -> 3253 conn._run_ddl_visitor(visitorcallable, element, **kwargs) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:2459, in Connection._run_ddl_visitor(self, visitorcallable, element, **kwargs) 2447 def _run_ddl_visitor( 2448 self, 2449 visitorcallable: Type[Union[SchemaGenerator, SchemaDropper]], 2450 element: SchemaItem, 2451 **kwargs: Any, 2452 ) -> None: 2453 \"\"\"run a DDL visitor. 2454 2455 This method is only here so that the MockConnection can change the 2456 options given to the visitor so that \"checkfirst\" is skipped. 2457 2458 \"\"\" -> 2459 visitorcallable(self.dialect, self, **kwargs).traverse_single(element) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py:664, in ExternalTraversal.traverse_single(self, obj, **kw) 662 meth = getattr(v, \"visit_%s\" % obj.__visit_name__, None) 663 if meth: --> 664 return meth(obj, **kw) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py:918, in SchemaGenerator.visit_metadata(self, metadata) 916 for table, fkcs in collection: 917 if table is not None: --> 918 self.traverse_single( 919 table, 920 create_ok=True, 921 include_foreign_key_constraints=fkcs, 922 _is_metadata_operation=True, 923 ) 924 else: 925 for fkc in fkcs: File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py:664, in ExternalTraversal.traverse_single(self, obj, **kw) 662 meth = getattr(v, \"visit_%s\" % obj.__visit_name__, None) 663 if meth: --> 664 return meth(obj, **kw) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py:956, in SchemaGenerator.visit_table(self, table, create_ok, include_foreign_key_constraints, _is_metadata_operation) 947 if not self.dialect.supports_alter: 948 # e.g., don't omit any foreign key constraints 949 include_foreign_key_constraints = None 951 CreateTable( 952 table, 953 include_foreign_key_constraints=( 954 include_foreign_key_constraints 955 ), --> 956 )._invoke_with(self.connection) 958 if hasattr(table, \"indexes\"): 959 for index in table.indexes: File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py:314, in ExecutableDDLElement._invoke_with(self, bind) 312 def _invoke_with(self, bind): 313 if self._should_execute(self.target, bind): --> 314 return bind.execute(self) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1418, in Connection.execute(self, statement, parameters, execution_options) 1416 raise exc.ObjectNotExecutableError(statement) from err 1417 else: -> 1418 return meth( 1419 self, 1420 distilled_parameters, 1421 execution_options or NO_OPTIONS, 1422 ) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py:180, in ExecutableDDLElement._execute_on_connection(self, connection, distilled_params, execution_options) 177 def _execute_on_connection( 178 self, connection, distilled_params, execution_options 179 ): --> 180 return connection._execute_ddl( 181 self, distilled_params, execution_options 182 ) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:1526, in Connection._execute_ddl(self, ddl, distilled_parameters, execution_options) 1522 schema_translate_map = exec_opts.get(\"schema_translate_map\", None) 1524 dialect = self.dialect -> 1526 compiled = ddl.compile( 1527 dialect=dialect, schema_translate_map=schema_translate_map 1528 ) 1529 ret = self._execute_context( 1530 dialect, 1531 dialect.execution_ctx_cls._init_ddl, (...) 1535 compiled, 1536 ) 1537 if self._has_events or self.engine._has_events: File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/elements.py:308, in CompilerElement.compile(self, bind, dialect, **kw) 303 url = util.preloaded.engine_url 304 dialect = url.URL.create( 305 self.stringify_dialect 306 ).get_dialect()() --> 308 return self._compiler(dialect, **kw) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/ddl.py:69, in BaseDDLElement._compiler(self, dialect, **kw) 65 def _compiler(self, dialect, **kw): 66 \"\"\"Return a compiler appropriate for this ClauseElement, given a 67 Dialect.\"\"\" ---> 69 return dialect.ddl_compiler(dialect, self, **kw) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/compiler.py:870, in Compiled.__init__(self, dialect, statement, schema_translate_map, render_schema_translate, compile_kwargs) 868 assert isinstance(statement, Executable) 869 self.execution_options = statement._execution_options --> 870 self.string = self.process(self.statement, **compile_kwargs) 872 if render_schema_translate: 873 self.string = self.preparer._render_schema_translates( 874 self.string, schema_translate_map 875 ) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/compiler.py:915, in Compiled.process(self, obj, **kwargs) 914 def process(self, obj: Visitable, **kwargs: Any) -> str: --> 915 return obj._compiler_dispatch(self, **kwargs) File ~/code/scg/atlas/.venv/lib/python3.11/site-packages/sqlalchemy/sql/visitors.py:141, in Visitable._generate_compiler_dispatch.DuckDB Engine Version
0.13.2
DuckDB Version
1.0.0
SQLAlchemy Version
2.0.35
Relevant log output
No response
Code of Conduct