Repository: trinodb/trino-python-client

Issue:
ModuleNotFoundError: No module named 'trino.sqlalchemy'
Trying out latest version of `trino==0.308` from PyPy.

Looks like it does not include the `sqlalchemy` module.

Am I being a noob?

Discussion:
dungdm93: Demos:
```
$ python setup.py sdist
$ cd dist/
$ tar -tvf trino-0.308.0.tar.gz 
drwxrwxr-x dungdm93/dungdm93 0 2021-12-04 16:03 trino-0.308.0/
-rw-rw-r-- dungdm93/dungdm93 1406 2021-12-04 16:03 trino-0.308.0/PKG-INFO
-rw-rw-r-- dungdm93/dungdm93 6980 2021-12-03 22:24 trino-0.308.0/README.md
-rw-rw-r-- dungdm93/dungdm93  109 2021-12-04 16:03 trino-0.308.0/setup.cfg
-rwxrwxr-x dungdm93/dungdm93 3102 2021-12-04 16:01 trino-0.308.0/setup.py
drwxrwxr-x dungdm93/dungdm93    0 2021-12-04 16:03 trino-0.308.0/trino/
-rw-rw-r-- dungdm93/dungdm93  778 2021-12-03 22:24 trino-0.308.0/trino/__init__.py
-rw-rw-r-- dungdm93/dungdm93 9919 2021-12-03 22:34 trino-0.308.0/trino/auth.py
-rw-rw-r-- dungdm93/dungdm93 20343 2021-12-03 22:24 trino-0.308.0/trino/client.py
-rw-rw-r-- dungdm93/dungdm93  1477 2021-12-03 22:24 trino-0.308.0/trino/constants.py
-rw-rw-r-- dungdm93/dungdm93 17284 2021-12-03 22:24 trino-0.308.0/trino/dbapi.py
-rw-rw-r-- dungdm93/dungdm93  5237 2021-12-03 22:24 trino-0.308.0/trino/exceptions.py
-rw-rw-r-- dungdm93/dungdm93   765 2021-12-03 22:24 trino-0.308.0/trino/logging.py
drwxrwxr-x dungdm93/dungdm93     0 2021-12-04 16:03 trino-0.308.0/trino/sqlalchemy/
-rw-rw-r-- dungdm93/dungdm93   657 2021-12-03 22:24 trino-0.308.0/trino/sqlalchemy/__init__.py
-rw-rw-r-- dungdm93/dungdm93  3203 2021-12-03 22:24 trino-0.308.0/trino/sqlalchemy/compiler.py
-rw-rw-r-- dungdm93/dungdm93  6739 2021-12-03 22:24 trino-0.308.0/trino/sqlalchemy/datatype.py
-rw-rw-r-- dungdm93/dungdm93 12407 2021-12-03 22:24 trino-0.308.0/trino/sqlalchemy/dialect.py
-rw-rw-r-- dungdm93/dungdm93  1058 2021-12-03 22:24 trino-0.308.0/trino/sqlalchemy/error.py
-rw-rw-r-- dungdm93/dungdm93  3429 2021-12-03 22:24 trino-0.308.0/trino/transaction.py
drwxrwxr-x dungdm93/dungdm93     0 2021-12-04 16:03 trino-0.308.0/trino.egg-info/
-rw-rw-r-- dungdm93/dungdm93  1406 2021-12-04 16:03 trino-0.308.0/trino.egg-info/PKG-INFO
-rw-rw-r-- dungdm93/dungdm93   485 2021-12-04 16:03 trino-0.308.0/trino.egg-info/SOURCES.txt
-rw-rw-r-- dungdm93/dungdm93     1 2021-12-04 16:03 trino-0.308.0/trino.egg-info/dependency_links.txt
-rw-rw-r-- dungdm93/dungdm93    69 2021-12-04 16:03 trino-0.308.0/trino.egg-info/entry_points.txt
-rw-rw-r-- dungdm93/dungdm93   199 2021-12-04 16:03 trino-0.308.0/trino.egg-info/requires.txt
-rw-rw-r-- dungdm93/dungdm93     6 2021-12-04 16:03 trino-0.308.0/trino.egg-info/top_level.txt
```
hashhar: Can you also add something like to `trino/__init__.py` so that sqlalchemy is also available if it's installed?

```python
try:
    from . import sqlalchemy
    __all__ += ['sqlalchemy']
except ImportError:
    import warnings
    warnings.warn('SQLAlchemy integration requires the sqlalchemy extra to be installed, try with '
                  'pip install trino[sqlalchemy]')
```
dungdm93: @hashhar So dbapi users (don't have `sqlalchemy` package installed) always receive this warning when `import trino`, right?
dungdm93: @hashhar So this will make dbapi users (don't have `sqlalchemy` package installed) always receive this warning when `import trino`, right?
hashhar: Ah, good point @dungdm93. I think we should place this warning in `trino/sqlalchemy/__init__.py` instead?

My intention was to raise this warning if users install the trino module but don't have the sqlalchemy extra installed.

Patch:
diff --git a/README.md b/README.md
index dff9e87..acffd61 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ This will query the `system.runtime.nodes` system tables that shows the nodes
 in the Trino cluster.
 
 The DBAPI implementation in `trino.dbapi` provides methods to retrieve fewer
-rows for example `Cursorfetchone()` or `Cursor.fetchmany()`. By default
+rows for example `Cursor.fetchone()` or `Cursor.fetchmany()`. By default
 `Cursor.fetchmany()` fetches one row. Please set
 `trino.dbapi.Cursor.arraysize` accordingly.
 
diff --git a/setup.py b/setup.py
index eea3833..4b0fedc 100755
--- a/setup.py
+++ b/setup.py
@@ -14,13 +14,12 @@
 
 import ast
 import re
-from setuptools import setup
 import textwrap
 
+from setuptools import setup, find_packages
 
 _version_re = re.compile(r"__version__\s+=\s+(.*)")
 
-
 with open("trino/__init__.py", "rb") as f:
     trino_version = _version_re.search(f.read().decode("utf-8"))
     assert trino_version is not None
@@ -38,7 +37,8 @@ tests_require = all_require + [
     "pytest",
     "pytest-runner",
     "pytz",
-    "click"]
+    "click",
+]
 
 setup(
     name="trino",
@@ -46,7 +46,7 @@ setup(
     author_email="python-client@trino.io",
     version=version,
     url="https://github.com/trinodb/trino-python-client",
-    packages=["trino"],
+    packages=find_packages(include=["trino", "trino.*"]),
     package_data={"": ["LICENSE", "README.md"]},
     description="Client for the Trino distributed SQL Engine",
     long_description=textwrap.dedent(
diff --git a/trino/auth.py b/trino/auth.py
index c3bedd7..2de1c1b 100644
--- a/trino/auth.py
+++ b/trino/auth.py
@@ -190,7 +190,7 @@ class _OAuth2TokenBearer(AuthBase):
         if not auth_info:
             raise exceptions.TrinoAuthError("Error: header WWW-Authenticate not available in the response.")
 
-        if not _OAuth2TokenBearer._BEARER_PREFIX.match(auth_info):
+        if not _OAuth2TokenBearer._BEARER_PREFIX.search(auth_info):
             raise exceptions.TrinoAuthError(f"Error: header info didn't match {auth_info}")
 
         auth_info_headers = parse_dict_header(_OAuth2TokenBearer._BEARER_PREFIX.sub("", auth_info, count=1))


Test patch:
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index bedeb6a..7a7bbca 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -421,6 +421,8 @@ def test_oauth2_authentication_missing_headers(header, error):
     'Bearer x_redirect_server="{redirect_server}", x_token_server="{token_server}", additional_challenge',
     'Bearer x_redirect_server="{redirect_server}", x_token_server="{token_server}", additional_challenge="value"',
     'Bearer x_token_server="{token_server}", x_redirect_server="{redirect_server}"',
+    'Basic realm="Trino", Bearer x_redirect_server="{redirect_server}", x_token_server="{token_server}"',
+    'Bearer x_redirect_server="{redirect_server}", x_token_server="{token_server}", Basic realm="Trino"',
 ])
 @httprettified
 def test_oauth2_header_parsing(header, sample_post_response_data):