Skip to content

setup.py user-management commands crash with AttributeError: 'PgAdmin' object has no attribute 'login_manager' in v9.14+ #9987

@andrewlecuyer

Description

@andrewlecuyer

Describe the bug

Running setup.py user management utilities (such as update-user or add-user) via the command line throws a fatal runtime exception. This structurally blocks configuration automation frameworks, configuration scripts, and Kubernetes operators from handling out-of-band administrative user changes or automated password rotations.

To Reproduce

Steps to reproduce the behavior:

  1. Install pgAdmin4 v9.15 (or v9.14).
  2. Execute the standard documented user update command from a terminal context:
python3 /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py update-user rhino@example.com --password abc123 --role Administrator
  1. See the error:
$ python3 /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py update-user rhino@example.com --password abc123 --role Administrator
╭────────────────────────────────────────────────────────────────────────────────────── Traceback (most recent call last) ───────────────────────────────────────────────────────────────────────────────────────╮
│ /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py:73 in wrap                                                                                                                                           │
│                                                                                                                                                                                                                │
│    70 │   │   if kwargs and kwargs.get('sqlite_path') is not None:                                                                                                                                             │
│    71 │   │   │   # update the sqlite path                                                                                                                                                                     │
│    72 │   │   │   config.SQLITE_PATH = kwargs['sqlite_path']                                                                                                                                                   │
│ ❱  73 │   │   return f(*args, **kwargs)                                                                                                                                                                        │
│    74 │                                                                                                                                                                                                        │
│    75 │   return wrap                                                                                                                                                                                          │
│    76                                                                                                                                                                                                          │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py:432 in update_user                                                                                                                                   │
│                                                                                                                                                                                                                │
│   429 │   │                                                                                                                                                                                                    │
│   430 │   │   app = create_app(config.APP_NAME + '-cli')                                                                                                                                                       │
│   431 │   │   with app.test_request_context():                                                                                                                                                                 │
│ ❱ 432 │   │   │   rid = ManageRoles.get_role(data['role'])                                                                                                                                                     │
│   433 │   │   │   if rid is None:                                                                                                                                                                              │
│   434 │   │   │   │   print("Role '{0}' does not exists.".format(data['role']))                                                                                                                                │
│   435 │   │   │   │   exit()                                                                                                                                                                                   │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py:154 in get_role                                                                                                                                      │
│                                                                                                                                                                                                                │
│   151 class ManageRoles:                                                                                                                                                                                       │
│   152 │   @staticmethod                                                                                                                                                                                        │
│   153 │   def get_role(role: str):                                                                                                                                                                             │
│ ❱ 154 │   │   app = create_app(config.APP_NAME + '-cli')                                                                                                                                                       │
│   155 │   │   usr = None                                                                                                                                                                                       │
│   156 │   │   with app.test_request_context():                                                                                                                                                                 │
│   157 │   │   │   usr = Role.query.filter_by(name=role).first()                                                                                                                                                │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/pgadmin4/pgadmin/__init__.py:498 in create_app                                                                                                                         │
│                                                                                                                                                                                                                │
│   495 │   │   │   run_migration_for_sqlite()                                                                                                                                                                   │
│   496 │   │                                                                                                                                                                                                    │
│   497 │   │   # Delete all the adhoc(temporary) servers from the pgAdmin database.                                                                                                                             │
│ ❱ 498 │   │   delete_adhoc_servers()                                                                                                                                                                           │
│   499 │                                                                                                                                                                                                        │
│   500 │   Mail(app)                                                                                                                                                                                            │
│   501                                                                                                                                                                                                          │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/pgadmin4/pgadmin/browser/server_groups/servers/utils.py:692 in delete_adhoc_servers                                                                                    │
│                                                                                                                                                                                                                │
│   689 │   during app startup (no user context), cleans all adhoc servers.                                                                                                                                      │
│   690 │   """
│   691 │   try:                                                                                                                                                                                                 │
│ ❱ 692 │   │   has_user = (has_request_context() and                                                                                                                                                            │
│   693 │   │   │   │   │   current_user and current_user.is_authenticated)                                                                                                                                      │
│   694 │   │   if sid is not None:                                                                                                                                                                              │
│   695 │   │   │   q = db.session.query(Server).filter(                                                                                                                                                         │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/werkzeug/local.py:318 in __get__                                                                                                                                       │
│                                                                                                                                                                                                                │
│   315 │   │   │   return self                                                                                                                                                                                  │
│   316 │   │                                                                                                                                                                                                    │
│   317 │   │   try:                                                                                                                                                                                             │
│ ❱ 318 │   │   │   obj = instance._get_current_object()                                                                                                                                                         │
│   319 │   │   except RuntimeError:                                                                                                                                                                             │
│   320 │   │   │   if self.fallback is None:                                                                                                                                                                    │
│   321 │   │   │   │   raise                                                                                                                                                                                    │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/werkzeug/local.py:526 in _get_current_object                                                                                                                           │
│                                                                                                                                                                                                                │
│   523 │   │   elif callable(local):                                                                                                                                                                            │
│   524 │   │   │                                                                                                                                                                                                │
│   525 │   │   │   def _get_current_object() -> T:                                                                                                                                                              │
│ ❱ 526 │   │   │   │   return get_name(local())                                                                                                                                                                 │
│   527 │   │                                                                                                                                                                                                    │
│   528 │   │   else:                                                                                                                                                                                            │
│   529 │   │   │   raise TypeError(f"Don't know how to proxy '{type(local)}'.")                                                                                                                                 │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/flask_login/utils.py:25 in <lambda>                                                                                                                                    │
│                                                                                                                                                                                                                │
│    22                                                                                                                                                                                                          │
│    23 #: A proxy for the current user. If no user is logged in, this will be an                                                                                                                                │
│    24 #: anonymous user                                                                                                                                                                                        │
│ ❱  25 current_user = LocalProxy(lambda: _get_user())                                                                                                                                                           │
│    26                                                                                                                                                                                                          │
│    27                                                                                                                                                                                                          │
│    28 def encode_cookie(payload, key=None):                                                                                                                                                                    │
│                                                                                                                                                                                                                │
│ /usr/local/lib/python3.11/site-packages/flask_login/utils.py:370 in _get_user                                                                                                                                  │
│                                                                                                                                                                                                                │
│   367 def _get_user():                                                                                                                                                                                         │
│   368 │   if has_request_context():                                                                                                                                                                            │
│   369 │   │   if "_login_user" not in g:                                                                                                                                                                       │
│ ❱ 370 │   │   │   current_app.login_manager._load_user()                                                                                                                                                       │
│   371 │   │                                                                                                                                                                                                    │
│   372 │   │   return g._login_user                                                                                                                                                                             │
│   373                                                                                                                                                                                                          │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
AttributeError: 'PgAdmin' object has no attribute 'login_manager'

Expected behavior

In v9.13, the command completes without any errors:

$ python3 /usr/local/lib/python3.11/site-packages/pgadmin4/setup.py update-user rhino@example.com --password abc123 --role Administrator
           User Details
+---------------------------------+
| Field       | Value             |
|-------------+-------------------|
| Username    | rhino@example.com |
| Email       | rhino@example.com |
| auth_source | internal          |
| role        | Administrator     |
| active      | True              |
+---------------------------------+

Error message

AttributeError: 'PgAdmin' object has no attribute 'login_manager'

Screenshots

N/A

Desktop (please complete the following information):

  • OS: Linux (UBI9)
  • pgAdmin version: 9.15
  • Mode: Server
  • Browser (if running in server mode): N/A
  • Package type: Python

Additional context

N/A

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions