So I am trying to use Neon as my db, for reading and updating a simple table. It was working wonders on local, but I am struggling to make it work on cloud. Iβve tried downgrading psycopg2 to 2.9.6, which made also to downgrade to python 3.11 but the error is the same. According to copilot and the sqlalchemy info, it is because the connection needs channel binding. Neon uses SCRAM-SHA-256 and it may work with MD5.
Note that since I need to update, I am making changes via using the Session directly with SQLAlchemy.
Relevant info:
https://steam-review.streamlit.app/
The error:
ββββββββββββββββββββββ Traceback (most recent call last) βββββββββββββββββββββββ
/home/adminuser/venv/lib/python3.11/site-packages/streamlit/runtime/scriptru
nner/exec_code.py:128 in exec_func_with_error_handling
/home/adminuser/venv/lib/python3.11/site-packages/streamlit/runtime/scriptru
nner/script_runner.py:669 in code_to_exec
/mount/src/steam-reviews-ai/main.py:300 in <module>
297 β with col_analysis:
298 β β if st.button("Generate Review Analysis"):
299 β β β appid = df[df["name"]==appname].index[0]
β± 300 β β β content_raw = manage_summary_by_appid(str(appid), total_re
301 β β β content = json.loads(content_raw)
302 β β β content = trim_factors(content, summary['total_positive']/
303 β β β with col_banner:
/mount/src/steam-reviews-ai/main.py:37 in manage_summary_by_appid
34 def manage_summary_by_appid(target_appid: str, total_reviews: int):
35 β conn = st.connection("neon", type="sql")
36 β session = conn.session
β± 37 β result = session.get(Summary, target_appid)
38 β json_summary = None
39 β if result is not None:
40 β β if check_fresh_summary(result, total_reviews):
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
3694 in get
3691 β β :return: The object instance, or ``None``.
3692 β β
3693 β β """ # noqa: E501
β± 3694 β β return self._get_impl(
3695 β β β entity,
3696 β β β ident,
3697 β β β loading.load_on_pk_identity,
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
3873 in _get_impl
3870 β β
3871 β β if options:
3872 β β β statement = statement.options(*options)
β± 3873 β β return db_load_fn(
3874 β β β self,
3875 β β β statement,
3876 β β β primary_key_identity,
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/loading.py:
694 in load_on_pk_identity
691 β β execution_options, {"_sa_orm_load_options": load_options}
692 β )
693 β result = (
β± 694 β β session.execute(
695 β β β q,
696 β β β params=params,
697 β β β execution_options=execution_options,
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
2365 in execute
2362 β β
2363 β β
2364 β β """
β± 2365 β β return self._execute_internal(
2366 β β β statement,
2367 β β β params,
2368 β β β execution_options=execution_options,
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
2241 in _execute_internal
2238 β β
2239 β β bind = self.get_bind(**bind_arguments)
2240 β β
β± 2241 β β conn = self._connection_for_bind(bind)
2242 β β
2243 β β if _scalar_result and not compile_state_cls:
2244 β β β if TYPE_CHECKING:
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
2110 in _connection_for_bind
2107 β β trans = self._transaction
2108 β β if trans is None:
2109 β β β trans = self._autobegin_t()
β± 2110 β β return trans._connection_for_bind(engine, execution_options)
2111 β
2112 β @overload
2113 β def _execute_internal(
in _connection_for_bind:2
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/state_chang
es.py:139 in _go
136 β β β self._current_fn = fn
137 β β β self._next_state = _StateChangeStates.CHANGE_IN_PROGRESS
138 β β β try:
β± 139 β β β β ret_value = fn(self, *arg, **kw)
140 β β β except:
141 β β β β raise
142 β β β else:
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/orm/session.py:
1189 in _connection_for_bind
1186 β β β β β β β "for the given Connection's Engine"
1187 β β β β β β )
1188 β β β β else:
β± 1189 β β β β β conn = bind.connect()
1190 β β β β β local_connect = True
1191 β β β
1192 β β β try:
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:
3273 in connect
3270 β β
3271 β β """
3272 β β
β± 3273 β β return self._connection_cls(self)
3274 β
3275 β def raw_connection(self) -> PoolProxiedConnection:
3276 β β """Return a "raw" DBAPI connection from the connection pool.
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:
147 in __init__
144 β β β try:
145 β β β β self._dbapi_connection = engine.raw_connection()
146 β β β except dialect.loaded_dbapi.Error as err:
β± 147 β β β β Connection._handle_dbapi_exception_noconnection(
148 β β β β β err, dialect, engine
149 β β β β )
150 β β β β raise
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:
2436 in _handle_dbapi_exception_noconnection
2433 β β β raise newraise.with_traceback(exc_info[2]) from e
2434 β β elif should_wrap:
2435 β β β assert sqlalchemy_exception is not None
β± 2436 β β β raise sqlalchemy_exception.with_traceback(exc_info[2]) fr
2437 β β else:
2438 β β β assert exc_info[1] is not None
2439 β β β raise exc_info[1].with_traceback(exc_info[2])
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:
145 in __init__
142 β β
143 β β if connection is None:
144 β β β try:
β± 145 β β β β self._dbapi_connection = engine.raw_connection()
146 β β β except dialect.loaded_dbapi.Error as err:
147 β β β β Connection._handle_dbapi_exception_noconnection(
148 β β β β β err, dialect, engine
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/base.py:
3297 in raw_connection
3294 β β β :ref:`dbapi_connections`
3295 β β
3296 β β """
β± 3297 β β return self.pool.connect()
3298
3299
3300 class OptionEngineMixin(log.Identified):
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:44
9 in connect
446 β β the pool.
447 β β
448 β β """
β± 449 β β return _ConnectionFairy._checkout(self)
450 β
451 β def _return_conn(self, record: ConnectionPoolEntry) -> None:
452 β β """Given a _ConnectionRecord, return it to the :class:`_pool.
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:12
64 in _checkout
1261 β β fairy: Optional[_ConnectionFairy] = None,
1262 β ) -> _ConnectionFairy:
1263 β β if not fairy:
β± 1264 β β β fairy = _ConnectionRecord.checkout(pool)
1265 β β β
1266 β β β if threadconns is not None:
1267 β β β β threadconns.current = weakref.ref(fairy)
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:71
3 in checkout
710 β β if TYPE_CHECKING:
711 β β β rec = cast(_ConnectionRecord, pool._do_get())
712 β β else:
β± 713 β β β rec = pool._do_get()
714 β β
715 β β try:
716 β β β dbapi_connection = rec.get_connection()
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py:17
9 in _do_get
176 β β β try:
177 β β β β return self._create_connection()
178 β β β except:
β± 179 β β β β with util.safe_reraise():
180 β β β β β self._dec_overflow()
181 β β β β raise
182 β β else:
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/util/langhelper
s.py:224 in __exit__
221 β β β exc_type, exc_value, exc_tb = self._exc_info
222 β β β assert exc_value is not None
223 β β β self._exc_info = None # remove potential circular refere
β± 224 β β β raise exc_value.with_traceback(exc_tb)
225 β β else:
226 β β β self._exc_info = None # remove potential circular refere
227 β β β assert value is not None
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/impl.py:17
7 in _do_get
174 β β
175 β β if self._inc_overflow():
176 β β β try:
β± 177 β β β β return self._create_connection()
178 β β β except:
179 β β β β with util.safe_reraise():
180 β β β β β self._dec_overflow()
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:39
0 in _create_connection
387 β def _create_connection(self) -> ConnectionPoolEntry:
388 β β """Called by subclasses to create a new ConnectionRecord."""
389 β β
β± 390 β β return _ConnectionRecord(self)
391 β
392 β def _invalidate(
393 β β self,
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:67
5 in __init__
672 β β
673 β β self.__pool = pool
674 β β if connect:
β± 675 β β β self.__connect()
676 β β self.finalize_callback = deque()
677 β
678 β dbapi_connection: Optional[DBAPIConnection]
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:90
1 in __connect
898 β β β pool.logger.debug("Created new connection %r", connection
899 β β β self.fresh = True
900 β β except BaseException as e:
β± 901 β β β with util.safe_reraise():
902 β β β β pool.logger.debug("Error on connect(): %s", e)
903 β β else:
904 β β β # in SQLAlchemy 1.4 the first_connect event is not used b
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/util/langhelper
s.py:224 in __exit__
221 β β β exc_type, exc_value, exc_tb = self._exc_info
222 β β β assert exc_value is not None
223 β β β self._exc_info = None # remove potential circular refere
β± 224 β β β raise exc_value.with_traceback(exc_tb)
225 β β else:
226 β β β self._exc_info = None # remove potential circular refere
227 β β β assert value is not None
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/pool/base.py:89
7 in __connect
894 β β self.dbapi_connection = None
895 β β try:
896 β β β self.starttime = time.time()
β± 897 β β β self.dbapi_connection = connection = pool._invoke_creator
898 β β β pool.logger.debug("Created new connection %r", connection
899 β β β self.fresh = True
900 β β except BaseException as e:
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/create.p
y:646 in connect
643 β β β β β if connection is not None:
644 β β β β β β return connection
645 β β β
β± 646 β β β return dialect.connect(*cargs, **cparams)
647 β β
648 β β creator = pop_kwarg("creator", connect)
649
/home/adminuser/venv/lib/python3.11/site-packages/sqlalchemy/engine/default.
py:625 in connect
622 β
623 β def connect(self, *cargs: Any, **cparams: Any) -> DBAPIConnection
624 β β # inherits the docstring from interfaces.Dialect.connect
β± 625 β β return self.loaded_dbapi.connect(*cargs, **cparams) # type:
626 β
627 β def create_connect_args(self, url: URL) -> ConnectArgsType:
628 β β # inherits the docstring from interfaces.Dialect.create_conne
/home/adminuser/venv/lib/python3.11/site-packages/psycopg2/__init__.py:122
in connect
119 β β kwasync['async_'] = kwargs.pop('async_')
120 β
121 β dsn = _ext.make_dsn(dsn, **kwargs)
β± 122 β conn = _connect(dsn, connection_factory=connection_factory, **kwas
123 β if cursor_factory is not None:
124 β β conn.cursor_factory = cursor_factory
125
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
OperationalError: (psycopg2.OperationalError) channel binding required but not
supported by server's authentication request
(Background on this error at: https://sqlalche.me/e/20/e3q8)