I am trying to get Hylang and SQLAlchemy to cooperate, but I can't seem to do it. I think it has something to do with how Flask-SQLAlchemy uses metaclasses to parse the database model, but I am not 100% sure. I tried creating a dictionary of all the defcolumn
s (which is defined below), but that gave me the same error. Here is my code:
(require hyrule [assoc defmacro/g!])
(import os)
(import subprocess)
(import sys)
(import flask [Flask redirect render_template request url_for])
(import flask-sqlalchemy [SQLAlchemy])
(import flask-migrate [Migrate])
(setv app (Flask __name__))
(setv path (os.path.join (os.path.expanduser "~/dbs") "development.db"))
(assoc app.config "SQLALCHEMY_DATABASE_URI" f"sqlite:///{path}")
(assoc app.config "SQLALCHEMY_TRACK_MODIFICATIONS" False)
(setv db (SQLAlchemy app))
(setv migrate (Migrate app db))
(defmacro defcolumn [name _column type #* args]
(if args
`(do {~name (db.Column ~type #** {~@args})})
`{~name (db.Column ~type)}))
(defclass Stream [db.Model]
(defcolumn "id" db.Column db.Integer "primary_key" True)
(defcolumn "name" db.Column (db.String 240) "unique" True "nullable" False)
(defcolumn "url" db.Column (db.String 240) "unique" True "nullable" False)
(defcolumn "currently-playing" db.Column db.Boolean "unique" False "default" False)
(defcolumn "created" db.Column
(db.DateTime :timezone True)
"unique" False
"default" (db.func.now))
(defcolumn "updated" db.Column
(db.DateTime :timezone True)
"unique" False
"default" (db.func.now))
(defn __init__ [self name url currently-playing]
(setv self.name name)
(setv self.url url)
(setv self.currently-playing currently-playing))
(defn __repr__ [self]
f"<Stream {self.name}>"))
And here is the error. As you can see, SQLAlchemy isn't getting the primary_key
key from the kwargs I am passing in:
danieljaouen on Daniels-MBP at …/pi-radio-hy via main (?)
hy app.hy
Traceback (most recent call last):
File "/opt/homebrew/bin/hy", line 8, in <module>
sys.exit(hy_main())
^^^^^^^^^
File "<frozen runpy>", line 286, in run_path
File "<frozen runpy>", line 98, in _run_module_code
File "<frozen runpy>", line 88, in _run_code
File "/Users/danieljaouen/src/pi-radio-hy/app.hy", line 25, in <module>
(defclass Stream [db.Model]
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/flask_sqlalchemy/model.py", line 92, in __init__
super().__init__(name, bases, d, **kwargs)
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/flask_sqlalchemy/model.py", line 144, in __init__
super().__init__(name, bases, d, **kwargs)
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_api.py", line 196, in __init__
_as_declarative(reg, cls, dict_)
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 247, in _as_declarative
return _MapperConfig.setup_mapping(registry, cls, dict_, None, {})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 328, in setup_mapping
return _ClassScanMapperConfig(
^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 582, in __init__
self._early_mapping(mapper_kw)
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 369, in _early_mapping
self.map(mapper_kw)
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/decl_base.py", line 1957, in map
mapper_cls(self.cls, self.local_table, **self.mapper_args),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<string>", line 2, in __init__
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/util/deprecations.py", line 281, in warned
return fn(*args, **kwargs) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/mapper.py", line 853, in __init__
self._configure_pks()
File "/opt/homebrew/Cellar/hy/0.28.0/libexec/lib/python3.12/site-packages/sqlalchemy/orm/mapper.py", line 1637, in _configure_pks
raise sa_exc.ArgumentError(
sqlalchemy.exc.ArgumentError: Mapper Mapper[Stream(stream)] could not assemble any primary key columns for mapped table 'stream'
This is my first time trying to translate an app from Python to Hylang, so any help here is greatly appreciated.
I'm not familiar with SQLAlchemy, but if I follow your code correctly, the form
(defcolumn "id" db.Column db.Integer "primary_key" True)
expands to
(do {"id" (db.Column db.Integer #** {"primary_key" True})})
which is unlikely to do anything useful, since you're constructing a literal dictionary ({"id" …}
) and then throwing it away. Perhaps you mean to use (setv "id" …)
instead.