diff --git a/alertaclient/__main__.py b/alertaclient/__main__.py
deleted file mode 100644
index d59779a..0000000
--- a/alertaclient/__main__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from alertaclient.cli import cli
-
-cli()
diff --git a/alertaclient/cli.py b/alertaclient/cli.py
index 0065906..6e3934c 100644
--- a/alertaclient/cli.py
+++ b/alertaclient/cli.py
@@ -9,8 +9,7 @@ from alertaclient.config import Config
 
 CONTEXT_SETTINGS = dict(
     auto_envvar_prefix='ALERTA',
-    default_map={'query': {'compact': True}},
-    help_option_names=['-h', '--help'],
+    default_map={'query': {'compact': True}}
 )
 cmd_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), 'commands'))
 
diff --git a/alertaclient/commands/cmd_login.py b/alertaclient/commands/cmd_login.py
index 24d99ba..8e83c96 100644
--- a/alertaclient/commands/cmd_login.py
+++ b/alertaclient/commands/cmd_login.py
@@ -9,9 +9,8 @@ from alertaclient.auth.token import Jwt
 
 
 @click.command('login', short_help='Login with user credentials')
-@click.argument('username', required=False)
 @click.pass_obj
-def cli(obj, username):
+def cli(obj):
     """Authenticate using Github, Gitlab, Google OAuth2 or Basic Auth
     username/password instead of using an API key."""
     client = obj['client']
@@ -24,12 +23,10 @@ def cli(obj, username):
         elif provider == 'gitlab':
             token = gitlab.login(client, obj['gitlab_url'], client_id)['token']
         elif provider == 'google':
-            if not username:
-                username = click.prompt('Email')
+            username = click.prompt('Email')
             token = google.login(client, username, client_id)['token']
         elif provider == 'basic':
-            if not username:
-                username = click.prompt('Email')
+            username = click.prompt('Email')
             password = click.prompt('Password', hide_input=True)
             token = client.login(username, password)['token']
         else:
@@ -39,10 +36,10 @@ def cli(obj, username):
         raise AuthError(e)
 
     jwt = Jwt()
-    preferred_username = jwt.parse(token)['preferred_username']
-    if preferred_username:
-        save_token(client.endpoint, preferred_username, token)
-        click.echo('Logged in as {}'.format(preferred_username))
+    username = jwt.parse(token)['preferred_username']
+    if username:
+        save_token(client.endpoint, username, token)
+        click.echo('Logged in as {}'.format(username))
     else:
         click.echo('Failed to login.')
         sys.exit(1)
diff --git a/alertaclient/models/alert.py b/alertaclient/models/alert.py
index 525c231..69ddab7 100644
--- a/alertaclient/models/alert.py
+++ b/alertaclient/models/alert.py
@@ -153,5 +153,5 @@ class Alert(object):
                 'receiveTime': DateTime.localtime(self.receive_time, timezone),
                 'lastReceiveId': self.last_receive_id,
                 'lastReceiveTime': DateTime.localtime(self.last_receive_time, timezone),
-                'history': [h.serialize(timezone) for h in self.history]
+                'history': self.history
             }

Error in Alerta class tabular 
 In Alerta CLI 5.2.0, I get an error in `alerta.tabular` method. 

Looking at the code (https://github.com/alerta/python-alerta-client/blob/master/alertaclient/models/alert.py#L156) I don't understand why there calling ` #'history': [h.serialize(timezone) for h in self.history]` instead of  `'history': [h for h in self.history]`

diff --git a/tests/test_formats.py b/tests/test_formats.py
new file mode 100644
index 0000000..19d11b9
--- /dev/null
+++ b/tests/test_formats.py
@@ -0,0 +1,105 @@
+import unittest
+
+import requests_mock
+
+from alertaclient.api import Client
+
+
+class FormatsTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.client = Client()
+
+        self.alert = """
+            {
+                "alert": {
+                  "attributes": {
+                    "ip": "127.0.0.1"
+                  },
+                  "correlate": [],
+                  "createTime": "2018-04-08T19:01:44.979Z",
+                  "customer": null,
+                  "duplicateCount": 0,
+                  "environment": "Development",
+                  "event": "foo",
+                  "group": "Misc",
+                  "history": [
+                    {
+                      "event": "foo",
+                      "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "severity": null,
+                      "status": "shelved",
+                      "text": "shelved by Test90",
+                      "type": "status",
+                      "updateTime": "2018-04-09T09:11:43.502Z",
+                      "value": null
+                    },
+                    {
+                      "event": "foo",
+                      "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "severity": null,
+                      "status": "open",
+                      "text": "bulk status change via console by test",
+                      "type": "status",
+                      "updateTime": "2018-04-24T17:52:40.088Z",
+                      "value": null
+                    },
+                    {
+                      "event": "foo",
+                      "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                      "severity": "minor",
+                      "status": "shelved",
+                      "text": "status change via console by Scott Wenzel",
+                      "type": "action",
+                      "updateTime": "2018-05-18T03:38:50.333Z",
+                      "value": null
+                    }
+                  ],
+                  "href": "https://alerta-api.herokuapp.com/alert/d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                  "id": "d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                  "lastReceiveId": "d1bb37cf-e976-429e-96f5-82b2a48aa50b",
+                  "lastReceiveTime": "2018-04-08T19:01:46.090Z",
+                  "origin": "alertad/fdaa33ca.lan",
+                  "previousSeverity": "indeterminate",
+                  "rawData": null,
+                  "receiveTime": "2018-04-08T19:01:46.090Z",
+                  "repeat": false,
+                  "resource": "quux",
+                  "service": [
+                    "Bar"
+                  ],
+                  "severity": "minor",
+                  "status": "shelved",
+                  "tags": [
+                    "watch:Scott Wenzel"
+                  ],
+                  "text": "",
+                  "timeout": 3600,
+                  "trendIndication": "moreSevere",
+                  "type": "exceptionAlert",
+                  "value": null
+                }
+            }
+        """
+
+    @requests_mock.mock()
+    def test_alert(self, m):
+        m.post('http://localhost:8080/alert', text=self.alert)
+        msg = {'event': 'foo', 'service': ['Bar']}
+
+        id, alert, message = self.client.send_alert(
+            environment='Production',
+            resource='quux',
+            **msg
+        )
+        alert_summary = alert.tabular(fields='summary', timezone='UTC')
+        self.assertEqual(alert_summary['id'], 'd1bb37cf')
+
+        alert_summary = alert.tabular(fields='details', timezone='UTC')
+        self.assertEqual(alert_summary['severity'], 'indeterminate -> minor')
+
+        alert_summary = alert.tabular(fields='all', timezone='UTC')
+        self.assertEqual(alert_summary['history'][0]['status'], 'shelved')
\ No newline at end of file

pip install -e .
parse_log_pytest
requirements.txt
nose pytest
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/alerta/python-alerta-client.git@f71b0aea9d8192c20bef25b5c8501fad7e249635#egg=alerta
certifi==2025.1.31
charset-normalizer==3.4.1
click==8.1.8
exceptiongroup==1.2.2
idna==3.10
iniconfig==2.1.0
nose==1.3.7
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytz==2025.2
requests==2.32.3
requests-mock==1.12.1
six==1.17.0
tabulate==0.9.0
tomli==2.2.1
urllib3==2.3.0

name: python-alerta-client
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - click==8.1.8
      - exceptiongroup==1.2.2
      - idna==3.10
      - iniconfig==2.1.0
      - nose==1.3.7
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytz==2025.2
      - requests==2.32.3
      - requests-mock==1.12.1
      - six==1.17.0
      - tabulate==0.9.0
      - tomli==2.2.1
      - urllib3==2.3.0
prefix: /opt/conda/envs/python-alerta-client

tests/test_formats.py::FormatsTestCase::test_alert
alertaclient/commands/cmd_login.py alertaclient/models/alert.py alertaclient/cli.py alertaclient/__main__.py
alertaclient/commands/cmd_login.py alertaclient/models/alert.py alertaclient/cli.py alertaclient/__main__.py