Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
###############################################################################

Authlib==1.6.*; python_version <= '3.9'
Authlib==1.7.*; python_version > '3.9'
Authlib==1.8.*; python_version > '3.9'
azure-identity==1.25.3
azure-mgmt-rdbms==10.1.1
# Azure CLI (a common companion package on Linux distros) still pins
Expand Down Expand Up @@ -44,16 +44,16 @@ Flask-WTF==1.3.*; python_version > '3.9'
Flask==3.1.*
google-api-python-client==2.*
google-auth-oauthlib==1.3.1; python_version <= '3.9'
google-auth-oauthlib==1.4.0; python_version > '3.9'
gssapi==1.11.*
google-auth-oauthlib==1.4.1; python_version > '3.9'
gssapi==1.12.*
jsonformatter~=0.3.4
keyring==25.*
ldap3==2.*
libgravatar==1.0.*
paramiko==3.5.1
psutil==7.2.*
psycopg[c]==3.2.13; python_version < '3.10'
psycopg[c]==3.3.4; python_version >= '3.10'
psycopg[c]==3.3.5; python_version >= '3.10'
Comment thread
coderabbitai[bot] marked this conversation as resolved.
pyotp==2.*
python-dateutil==2.*
pytz==2026.*
Expand Down
96 changes: 48 additions & 48 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@
],
"license": "PostgreSQL",
"devDependencies": {
"@babel/core": "^7.29.6",
"@babel/eslint-parser": "^7.28.6",
"@babel/eslint-plugin": "^7.27.1",
"@babel/plugin-syntax-jsx": "^7.28.6",
"@babel/plugin-transform-class-properties": "^7.28.6",
"@babel/plugin-transform-object-rest-spread": "^7.28.6",
"@babel/plugin-transform-runtime": "^7.29.0",
"@babel/preset-env": "^7.29.2",
"@babel/preset-react": "^7.28.5",
"@babel/preset-typescript": "^7.28.5",
"@babel/core": "^7.29.7",
"@babel/eslint-parser": "^7.29.7",
"@babel/eslint-plugin": "^7.29.7",
"@babel/plugin-syntax-jsx": "^7.29.7",
"@babel/plugin-transform-class-properties": "^7.29.7",
"@babel/plugin-transform-object-rest-spread": "^7.29.7",
"@babel/plugin-transform-runtime": "^7.29.7",
"@babel/preset-env": "^7.29.7",
"@babel/preset-react": "^7.29.7",
"@babel/preset-typescript": "^7.29.7",
"@emotion/memoize": "^0.9.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@emotion/utils": "^1.4.2",
"@svgr/webpack": "^8.1.0",
"@testing-library/dom": "10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "16.3.2",
"@testing-library/jest-dom": "^6.10.0",
"@testing-library/react": "16.3.3",
"@testing-library/user-event": "^14.6.3",
"@types/jest": "^30.0.0",
"autoprefixer": "^10.5.4",
Expand All @@ -33,21 +33,21 @@
"browserify": "^17.0.1",
"buffer": "^6.0.3",
"copy-webpack-plugin": "^14.0.0",
"core-js": "^3.49.0",
"core-js": "^3.50.0",
"cross-env": "^10.1.0",
"css-loader": "^7.1.4",
"css-loader": "^7.1.5",
"css-minimizer-webpack-plugin": "^8.0.0",
"eslint": "^9.39.4",
"eslint-plugin-jest": "^29.15.5",
"eslint": "^9.39.5",
"eslint-plugin-jest": "^29.16.6",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-unused-imports": "^4.4.1",
"exports-loader": "^5.0.0",
"globals": "^17.7.0",
"globals": "^17.12.0",
"html-react-parser": "^5.2.17",
"image-minimizer-webpack-plugin": "^5.0.0",
"imports-loader": "^5.0.0",
"jest": "^30.4.2",
"jest-environment-jsdom": "^30.4.1",
"jest": "^30.5.1",
"jest-environment-jsdom": "^30.5.1",
"loader-utils": "^3.3.1",
"mini-css-extract-plugin": "^2.10.2",
"postcss-loader": "^8.2.1",
Expand All @@ -57,20 +57,20 @@
"shim-loader": "^1.0.1",
"style-loader": "^4.0.0",
"stylis": "^4.4.0",
"svgo": "4.0.2",
"svgo": "4.1.0",
"svgo-loader": "^5.0.0",
"terser-webpack-plugin": "^5.6.1",
"typescript": "^6.0.3",
"typescript-eslint": "^8.65.0",
"typescript-eslint": "^8.69.0",
"url-loader": "^4.1.1",
"webfonts-loader": "^8.1.1",
"webpack": "^5.108.4",
"webpack-bundle-analyzer": "^5.3.1",
"webpack-bundle-analyzer": "^5.3.2",
"webpack-cli": "^6.0.1",
"yarn-audit-html": "7.3.2"
},
"optionalDependencies": {
"sharp": "^0.35.3"
"sharp": "^0.35.4"
},
"dependencies": {
"@codemirror/lang-json": "^6.0.2",
Expand All @@ -80,63 +80,63 @@
"@emotion/sheet": "^1.4.0",
"@fluentui/keyboard-key": "^0.4.23",
"@fortawesome/fontawesome-free": "latest",
"@mui/icons-material": "^7.3.10",
"@mui/material": "^7.3.10",
"@mui/x-date-pickers": "^8.28.3",
"@mui/icons-material": "^7.3.11",
"@mui/material": "^7.3.11",
"@mui/x-date-pickers": "^8.29.3",
"@nozbe/microfuzz": "^1.0.0",
"@projectstorm/react-diagrams": "^7.0.4",
"@simonwep/pickr": "~1.9.1",
"@szhsin/react-menu": "^4.5.2",
"@tanstack/react-query": "^5.101.4",
"@tanstack/react-query": "^5.102.8",
"@tanstack/react-table": "^8.21.3",
"@tanstack/react-virtual": "^3.14.9",
"@types/react": "^19.2.17",
"@types/react-dom": "^19.2.3",
"@tanstack/react-virtual": "^3.14.10",
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.5",
"@xterm/addon-fit": "^0.11.0",
"@xterm/addon-search": "^0.16.0",
"@xterm/addon-web-links": "^0.12.0",
"@xterm/xterm": "^6.0.0",
"ajv": "^8.20.0",
"anti-trojan-source": "^1.12.1",
"anti-trojan-source": "^1.12.2",
"aspen-decorations": "^1.1.1",
"axios": "^1.18.1",
"axios": "^1.20.0",
"babelify": "~10.0.0",
"bignumber.js": "^10.0.2",
"brace": "^0.11.1",
"chart.js": "^4.5.1",
"chartjs-plugin-zoom": "^2.2.0",
"codemirror": "^6.0.2",
"codemirror": "^6.65.7",
"convert-units": "^2.3.4",
"date-fns": "^4.4.0",
"diff-arrays-of-objects": "^1.1.10",
"dompurify": "^3.4.13",
"hotkeys-js": "^4.0.4",
"diff-arrays-of-objects": "^1.1.11",
"dompurify": "^3.4.14",
"hotkeys-js": "^4.0.7",
"html-to-image": "1.11.13",
"immutability-helper": "^3.1.1",
"insert-if": "^1.2.0",
"ip-address": "^10.3.1",
"ip-address": "^10.7.0",
"json-bignumber": "^1.1.1",
"leaflet": "^1.9.4",
"lodash": "4.*",
"lossless-json": "^4.3.0",
"marked": "^18.0.7",
"lossless-json": "^4.3.1",
"marked": "^18.0.11",
"moment": "^2.30.1",
"moment-timezone": "^0.6.3",
"notificar": "^1.0.1",
"notistack": "^3.0.2",
"papaparse": "^5.5.4",
"papaparse": "^5.7.0",
"path-fx": "^2.1.2",
"postcss": "^8.5.23",
"rc-dock": "^4.0.0-alpha.2",
"react": "^19.2.7",
"react-arborist": "^3.5.0",
"postcss": "^8.5.26",
"rc-dock": "^4.0.0-alpha.3",
"react": "^19.2.8",
"react-arborist": "^3.16.0",
"react-aspen": "^1.2.0",
"react-checkbox-tree": "^2.0.2",
"react-data-grid": "https://github.com/pgadmin-org/react-data-grid.git#8ddaa7bed99c8329e39b8ff37ba156f7fc8e85d4",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^19.2.7",
"react-draggable": "^4.7.0",
"react-dom": "^19.2.8",
"react-draggable": "^4.7.1",
"react-dropzone": "^15.0.0",
"react-frame-component": "~5.2.6",
"react-leaflet": "^4.2.1",
Expand All @@ -154,9 +154,9 @@
"uplot-react": "^1.2.4",
"use-resize-observer": "^10.0.0",
"valid-filename": "^4.0.0",
"vanilla-jsoneditor": "^3.12.0",
"vanilla-jsoneditor": "^3.13.0",
"wkx": "^0.5.0",
"zustand": "^5.0.14"
"zustand": "^5.0.15"
},
"resolutions": {
"rc-resize-observer": "1.4.0",
Expand Down
11 changes: 5 additions & 6 deletions web/pgadmin/utils/driver/psycopg3/encoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ def get_encoding(key):
current_app.logger.error(e)
postgres_encoding = 'utf-8'

python_encoding = psycopg._encodings._py_codecs.get(postgres_encoding,
'utf-8')
python_encoding = psycopg._encodings.py_codecs.get(
postgres_encoding.upper().encode(), 'utf-8')

_dict = encode_dict.get(postgres_encoding.upper(),
[postgres_encoding,
Expand All @@ -61,9 +61,8 @@ def configure_driver_encodings(encodings):

for key, val in encode_dict.items():
_, python_encoding = val
psycopg._encodings._py_codecs[key] = python_encoding
psycopg._encodings.py_codecs[key.encode()] = python_encoding

encodings.update((k.encode(), v
) for k, v in psycopg._encodings._py_codecs.items())
encodings.update(psycopg._encodings.py_codecs)
psycopg._encodings.pg_codecs = {
v: k.encode() for k, v in psycopg._encodings._py_codecs.items()}
v: k for k, v in psycopg._encodings.py_codecs.items()}
67 changes: 67 additions & 0 deletions web/pgadmin/utils/driver/psycopg3/tests/test_encoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################

"""
Unit tests for pgadmin.utils.driver.psycopg3.encoding.

These guard against psycopg restructuring its private
psycopg._encodings module (e.g. 3.3.5 changed _py_codecs from a dict
to a tuple of alias groups, breaking configure_driver_encodings()).
They don't need a live database connection.
"""

import psycopg

from pgadmin.utils.driver.psycopg3.encoding import get_encoding, \
configure_driver_encodings
from pgadmin.utils.route import BaseTestGenerator


class TestEncoding(BaseTestGenerator):
"""Validate get_encoding()/configure_driver_encodings() against
whatever shape the installed psycopg version's encoding tables
have."""

scenarios = [
('UTF8 maps to the utf-8 python codec',
dict(key='UTF8', expected=['utf-8', 'utf-8'])),
('LATIN1 maps to the iso8859-1 python codec',
dict(key='LATIN1', expected=['ISO88591', 'iso8859-1'])),
('SQL_ASCII falls back to the pgAdmin-only override',
dict(key='SQL_ASCII', expected=['utf-8', 'utf-8'])),
('EUC_TW falls back to the pgAdmin-only override',
dict(key='EUC_TW', expected=['utf-8', 'utf-8'])),
('UNICODE falls back to the pgAdmin-only override',
dict(key='UNICODE', expected=['utf-8', 'utf-8'])),
('the ascii special-case resolves via raw_unicode_escape',
dict(key='ascii', expected=['SQLASCII', 'raw-unicode-escape'])),
]

def setUp(self):
# No DB connection needed for this test.
pass

def runTest(self):
encodings = {}
configure_driver_encodings(encodings)

with self.app.app_context():
self.assertEqual(get_encoding(self.key), self.expected)

# py_codecs/pg_codecs must stay plain dicts and stay in sync,
# regardless of how psycopg represents its internal encoding
# table (dict in <=3.3.4, tuple-of-aliases in >=3.3.5).
self.assertIsInstance(psycopg._encodings.py_codecs, dict)
self.assertIsInstance(psycopg._encodings.pg_codecs, dict)
# pg_codecs is the reverse of py_codecs (python codec -> one of
# its PG names); every value it holds must round-trip back to
# the same python codec through py_codecs.
for python_codec, pg_name in psycopg._encodings.pg_codecs.items():
self.assertEqual(
psycopg._encodings.py_codecs.get(pg_name), python_codec)
4 changes: 2 additions & 2 deletions web/regression/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ pbr==7.0.3
pycodestyle>=2.14.0
python-mimeparse==2.0.0
selenium==4.44.0; python_version <= '3.9'
selenium==4.47.0; python_version > '3.9'
selenium==4.48.0; python_version > '3.9'
testscenarios==0.5.0; python_version <= '3.9'
testscenarios==0.6.2; python_version > '3.9'
testscenarios==0.7.0; python_version > '3.9'
testtools==2.7.2; python_version <= '3.9'
testtools==2.9.1; python_version > '3.9'
traceback2==1.4.0
Loading
Loading