Repository: macbre/sql-metadata

Issue:
Query including Distinct not working
```
sql_new="SELECT DISTINCT customer_id FROM table"

parsed = Parser(sql_new)

print("columns-->", parsed.columns)
```
Result:
`columns--> []`

The above query is not working . 

Discussion:

Patch:
diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..ea05802
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,3 @@
+[flake8]
+max-line-length = 88
+max-complexity = 8
\ No newline at end of file
diff --git a/poetry.lock b/poetry.lock
index 30859dd..daac339 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -30,17 +30,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "attrs"
-version = "20.3.0"
+version = "21.2.0"
 description = "Classes Without Boilerplate"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"]
-docs = ["furo", "sphinx", "zope.interface"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
 
 [[package]]
 name = "black"
@@ -76,20 +76,27 @@ optional = false
 python-versions = "*"
 
 [[package]]
-name = "chardet"
-version = "4.0.0"
-description = "Universal encoding detector for Python 2 and 3"
+name = "charset-normalizer"
+version = "2.0.3"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.5.0"
+
+[package.extras]
+unicode_backport = ["unicodedata2"]
 
 [[package]]
 name = "click"
-version = "7.1.2"
+version = "8.0.1"
 description = "Composable command line interface toolkit"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6"
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
 
 [[package]]
 name = "colorama"
@@ -145,17 +152,31 @@ category = "dev"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "flake8"
+version = "3.9.2"
+description = "the modular source code checker: pep8 pyflakes and co"
+category = "dev"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
+
+[package.dependencies]
+importlib-metadata = {version = "*", markers = "python_version < \"3.8\""}
+mccabe = ">=0.6.0,<0.7.0"
+pycodestyle = ">=2.7.0,<2.8.0"
+pyflakes = ">=2.3.0,<2.4.0"
+
 [[package]]
 name = "idna"
-version = "2.10"
+version = "3.2"
 description = "Internationalized Domain Names in Applications (IDNA)"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.5"
 
 [[package]]
 name = "importlib-metadata"
-version = "3.4.0"
+version = "4.6.1"
 description = "Read metadata from Python packages"
 category = "dev"
 optional = false
@@ -167,7 +188,8 @@ zipp = ">=0.5"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
+perf = ["ipython"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
 
 [[package]]
 name = "iniconfig"
@@ -179,24 +201,25 @@ python-versions = "*"
 
 [[package]]
 name = "isort"
-version = "5.7.0"
+version = "5.9.2"
 description = "A Python utility / library to sort Python imports."
 category = "dev"
 optional = false
-python-versions = ">=3.6,<4.0"
+python-versions = ">=3.6.1,<4.0"
 
 [package.extras]
 pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
 requirements_deprecated_finder = ["pipreqs", "pip-api"]
 colors = ["colorama (>=0.4.3,<0.5.0)"]
+plugins = ["setuptools"]
 
 [[package]]
 name = "lazy-object-proxy"
-version = "1.4.3"
+version = "1.6.0"
 description = "A fast and thorough lazy object proxy."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
 [[package]]
 name = "mccabe"
@@ -216,22 +239,22 @@ python-versions = "*"
 
 [[package]]
 name = "packaging"
-version = "20.9"
+version = "21.0"
 description = "Core utilities for Python packages"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
 
 [package.dependencies]
 pyparsing = ">=2.0.2"
 
 [[package]]
 name = "pathspec"
-version = "0.8.1"
+version = "0.9.0"
 description = "Utility library for gitignore style pattern matching of file paths."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
 [[package]]
 name = "pluggy"
@@ -255,16 +278,32 @@ category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
+[[package]]
+name = "pycodestyle"
+version = "2.7.0"
+description = "Python style guide checker"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
+[[package]]
+name = "pyflakes"
+version = "2.3.1"
+description = "passive checker of Python programs"
+category = "dev"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+
 [[package]]
 name = "pylint"
-version = "2.9.4"
+version = "2.9.5"
 description = "python code static checker"
 category = "dev"
 optional = false
 python-versions = "~=3.6"
 
 [package.dependencies]
-astroid = ">=2.6.4,<2.7"
+astroid = ">=2.6.5,<2.7"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
 isort = ">=4.2.5,<6"
 mccabe = ">=0.6,<0.7"
@@ -318,7 +357,7 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale
 
 [[package]]
 name = "regex"
-version = "2020.11.13"
+version = "2021.7.6"
 description = "Alternative regular expression module, to replace re."
 category = "dev"
 optional = false
@@ -326,21 +365,21 @@ python-versions = "*"
 
 [[package]]
 name = "requests"
-version = "2.25.1"
+version = "2.26.0"
 description = "Python HTTP for Humans."
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
 [package.dependencies]
 certifi = ">=2017.4.17"
-chardet = ">=3.0.2,<5"
-idna = ">=2.5,<3"
+charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
+idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
 urllib3 = ">=1.21.1,<1.27"
 
 [package.extras]
-security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
 socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
+use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
 
 [[package]]
 name = "sqlparse"
@@ -368,7 +407,7 @@ python-versions = ">=3.6"
 
 [[package]]
 name = "typed-ast"
-version = "1.4.2"
+version = "1.4.3"
 description = "a fork of Python 2 and 3 ast modules with type comment support"
 category = "dev"
 optional = false
@@ -376,7 +415,7 @@ python-versions = "*"
 
 [[package]]
 name = "typing-extensions"
-version = "3.7.4.3"
+version = "3.10.0.0"
 description = "Backported and Experimental Type Hints for Python 3.5+"
 category = "dev"
 optional = false
@@ -384,7 +423,7 @@ python-versions = "*"
 
 [[package]]
 name = "urllib3"
-version = "1.26.5"
+version = "1.26.6"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
 category = "dev"
 optional = false
@@ -405,20 +444,20 @@ python-versions = "*"
 
 [[package]]
 name = "zipp"
-version = "3.4.0"
+version = "3.5.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
 category = "dev"
 optional = false
 python-versions = ">=3.6"
 
 [package.extras]
-docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
+testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.6.2"
-content-hash = "025c9f558957fbe2b5b508e08db7997a0347d67f16b834768d335588f406b0f5"
+content-hash = "0c53f2c7edcae820a4decdf258bb20a3fd322a2f2800e82a4cb1e83753e830d6"
 
 [metadata.files]
 appdirs = [
@@ -434,8 +473,8 @@ atomicwrites = [
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"},
-    {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"},
+    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
+    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
 ]
 black = [
     {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"},
@@ -445,13 +484,13 @@ certifi = [
     {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
     {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
 ]
-chardet = [
-    {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
-    {file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
+charset-normalizer = [
+    {file = "charset-normalizer-2.0.3.tar.gz", hash = "sha256:c46c3ace2d744cfbdebceaa3c19ae691f53ae621b39fd7570f59d14fb7f2fd12"},
+    {file = "charset_normalizer-2.0.3-py3-none-any.whl", hash = "sha256:88fce3fa5b1a84fdcb3f603d889f723d1dd89b26059d0123ca435570e848d5e1"},
 ]
 click = [
-    {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
-    {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
+    {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
+    {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
 ]
 colorama = [
     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
@@ -522,44 +561,49 @@ dataclasses = [
 docopt = [
     {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
 ]
+flake8 = [
+    {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
+    {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
+]
 idna = [
-    {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
-    {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
+    {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
+    {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"},
 ]
 importlib-metadata = [
-    {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"},
-    {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"},
+    {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"},
+    {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"},
 ]
 iniconfig = [
     {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
     {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
 ]
 isort = [
-    {file = "isort-5.7.0-py3-none-any.whl", hash = "sha256:fff4f0c04e1825522ce6949973e83110a6e907750cd92d128b0d14aaaadbffdc"},
-    {file = "isort-5.7.0.tar.gz", hash = "sha256:c729845434366216d320e936b8ad6f9d681aab72dc7cbc2d51bedc3582f3ad1e"},
+    {file = "isort-5.9.2-py3-none-any.whl", hash = "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813"},
+    {file = "isort-5.9.2.tar.gz", hash = "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"},
 ]
 lazy-object-proxy = [
-    {file = "lazy-object-proxy-1.4.3.tar.gz", hash = "sha256:f3900e8a5de27447acbf900b4750b0ddfd7ec1ea7fbaf11dfa911141bc522af0"},
-    {file = "lazy_object_proxy-1.4.3-cp27-cp27m-macosx_10_13_x86_64.whl", hash = "sha256:a2238e9d1bb71a56cd710611a1614d1194dc10a175c1e08d75e1a7bcc250d442"},
-    {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win32.whl", hash = "sha256:efa1909120ce98bbb3777e8b6f92237f5d5c8ea6758efea36a473e1d38f7d3e4"},
-    {file = "lazy_object_proxy-1.4.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4677f594e474c91da97f489fea5b7daa17b5517190899cf213697e48d3902f5a"},
-    {file = "lazy_object_proxy-1.4.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:0c4b206227a8097f05c4dbdd323c50edf81f15db3b8dc064d08c62d37e1a504d"},
-    {file = "lazy_object_proxy-1.4.3-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:d945239a5639b3ff35b70a88c5f2f491913eb94871780ebfabb2568bd58afc5a"},
-    {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win32.whl", hash = "sha256:9651375199045a358eb6741df3e02a651e0330be090b3bc79f6d0de31a80ec3e"},
-    {file = "lazy_object_proxy-1.4.3-cp34-cp34m-win_amd64.whl", hash = "sha256:eba7011090323c1dadf18b3b689845fd96a61ba0a1dfbd7f24b921398affc357"},
-    {file = "lazy_object_proxy-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:48dab84ebd4831077b150572aec802f303117c8cc5c871e182447281ebf3ac50"},
-    {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:ca0a928a3ddbc5725be2dd1cf895ec0a254798915fb3a36af0964a0a4149e3db"},
-    {file = "lazy_object_proxy-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:194d092e6f246b906e8f70884e620e459fc54db3259e60cf69a4d66c3fda3449"},
-    {file = "lazy_object_proxy-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:97bb5884f6f1cdce0099f86b907aa41c970c3c672ac8b9c8352789e103cf3156"},
-    {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:cb2c7c57005a6804ab66f106ceb8482da55f5314b7fcb06551db1edae4ad1531"},
-    {file = "lazy_object_proxy-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:8d859b89baf8ef7f8bc6b00aa20316483d67f0b1cbf422f5b4dc56701c8f2ffb"},
-    {file = "lazy_object_proxy-1.4.3-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:1be7e4c9f96948003609aa6c974ae59830a6baecc5376c25c92d7d697e684c08"},
-    {file = "lazy_object_proxy-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d74bb8693bf9cf75ac3b47a54d716bbb1a92648d5f781fc799347cfc95952383"},
-    {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:9b15f3f4c0f35727d3a0fba4b770b3c4ebbb1fa907dbcc046a1d2799f3edd142"},
-    {file = "lazy_object_proxy-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9254f4358b9b541e3441b007a0ea0764b9d056afdeafc1a5569eee1cc6c1b9ea"},
-    {file = "lazy_object_proxy-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:a6ae12d08c0bf9909ce12385803a543bfe99b95fe01e752536a60af2b7797c62"},
-    {file = "lazy_object_proxy-1.4.3-cp38-cp38-win32.whl", hash = "sha256:5541cada25cd173702dbd99f8e22434105456314462326f06dba3e180f203dfd"},
-    {file = "lazy_object_proxy-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:59f79fef100b09564bc2df42ea2d8d21a64fdcda64979c0fa3db7bdaabaf6239"},
+    {file = "lazy-object-proxy-1.6.0.tar.gz", hash = "sha256:489000d368377571c6f982fba6497f2aa13c6d1facc40660963da62f5c379726"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:c6938967f8528b3668622a9ed3b31d145fab161a32f5891ea7b84f6b790be05b"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win32.whl", hash = "sha256:ebfd274dcd5133e0afae738e6d9da4323c3eb021b3e13052d8cbd0e457b1256e"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93"},
+    {file = "lazy_object_proxy-1.6.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d900d949b707778696fdf01036f58c9876a0d8bfe116e8d220cfd4b15f14e741"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5743a5ab42ae40caa8421b320ebf3a998f89c85cdc8376d6b2e00bd12bd1b587"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:bf34e368e8dd976423396555078def5cfc3039ebc6fc06d1ae2c5a65eebbcde4"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win32.whl", hash = "sha256:b579f8acbf2bdd9ea200b1d5dea36abd93cabf56cf626ab9c744a432e15c815f"},
+    {file = "lazy_object_proxy-1.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:4f60460e9f1eb632584c9685bccea152f4ac2130e299784dbaf9fae9f49891b3"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7124f52f3bd259f510651450e18e0fd081ed82f3c08541dffc7b94b883aa981"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:22ddd618cefe54305df49e4c069fa65715be4ad0e78e8d252a33debf00f6ede2"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win32.whl", hash = "sha256:9d397bf41caad3f489e10774667310d73cb9c4258e9aed94b9ec734b34b495fd"},
+    {file = "lazy_object_proxy-1.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a5045889cc2729033b3e604d496c2b6f588c754f7a62027ad4437a7ecc4837"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:17e0967ba374fc24141738c69736da90e94419338fd4c7c7bef01ee26b339653"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:410283732af311b51b837894fa2f24f2c0039aa7f220135192b38fcc42bd43d3"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-win32.whl", hash = "sha256:85fb7608121fd5621cc4377a8961d0b32ccf84a7285b4f1d21988b2eae2868e8"},
+    {file = "lazy_object_proxy-1.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:d1c2676e3d840852a2de7c7d5d76407c772927addff8d742b9808fe0afccebdf"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b865b01a2e7f96db0c5d12cfea590f98d8c5ba64ad222300d93ce6ff9138bcad"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4732c765372bd78a2d6b2150a6e99d00a78ec963375f236979c0626b97ed8e43"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:9698110e36e2df951c7c36b6729e96429c9c32b3331989ef19976592c5f3c77a"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-win32.whl", hash = "sha256:1fee665d2638491f4d6e55bd483e15ef21f6c8c2095f235fef72601021e64f61"},
+    {file = "lazy_object_proxy-1.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b"},
 ]
 mccabe = [
     {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
@@ -570,12 +614,12 @@ mypy-extensions = [
     {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
 ]
 packaging = [
-    {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
-    {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
+    {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
+    {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
 ]
 pathspec = [
-    {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"},
-    {file = "pathspec-0.8.1.tar.gz", hash = "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd"},
+    {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
+    {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
 ]
 pluggy = [
     {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
@@ -585,9 +629,17 @@ py = [
     {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"},
     {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"},
 ]
+pycodestyle = [
+    {file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
+    {file = "pycodestyle-2.7.0.tar.gz", hash = "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef"},
+]
+pyflakes = [
+    {file = "pyflakes-2.3.1-py2.py3-none-any.whl", hash = "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3"},
+    {file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
+]
 pylint = [
-    {file = "pylint-2.9.4-py3-none-any.whl", hash = "sha256:2a971129fb2d594068913a7e531d4b6d2785b2a68c6857e2baa40d3214da30f4"},
-    {file = "pylint-2.9.4.tar.gz", hash = "sha256:a622c4c4c79dc8fe5e784efccacec3afe9d5e5ffab5fda2264fb5afa7c9b5797"},
+    {file = "pylint-2.9.5-py3-none-any.whl", hash = "sha256:748f81e5776d6273a6619506e08f1b48ff9bcb8198366a56821cf11aac14fc87"},
+    {file = "pylint-2.9.5.tar.gz", hash = "sha256:1f333dc72ef7f5ea166b3230936ebcfb1f3b722e76c980cb9fe6b9f95e8d3172"},
 ]
 pyparsing = [
     {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
@@ -602,51 +654,51 @@ pytest-cov = [
     {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
 ]
 regex = [
-    {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"},
-    {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"},
-    {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"},
-    {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"},
-    {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"},
-    {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"},
-    {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"},
-    {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"},
-    {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"},
-    {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"},
-    {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"},
-    {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"},
-    {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"},
-    {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"},
-    {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"},
-    {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"},
-    {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"},
+    {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"},
+    {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"},
+    {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"},
+    {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"},
+    {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"},
+    {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"},
+    {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"},
+    {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"},
+    {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"},
+    {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"},
+    {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"},
+    {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"},
+    {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"},
+    {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"},
+    {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"},
+    {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"},
+    {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"},
 ]
 requests = [
-    {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
-    {file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
+    {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
+    {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
 ]
 sqlparse = [
     {file = "sqlparse-0.4.1-py3-none-any.whl", hash = "sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0"},
@@ -661,50 +713,50 @@ tomli = [
     {file = "tomli-1.0.4.tar.gz", hash = "sha256:be670d0d8d7570fd0ea0113bd7bb1ba3ac6706b4de062cc4c952769355c9c268"},
 ]
 typed-ast = [
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"},
-    {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"},
-    {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"},
-    {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"},
-    {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"},
-    {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"},
-    {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"},
-    {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"},
-    {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"},
-    {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"},
-    {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"},
-    {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"},
-    {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
+    {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
+    {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
+    {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
+    {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
+    {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
+    {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
+    {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
+    {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
+    {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
+    {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
+    {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
+    {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
 ]
 typing-extensions = [
-    {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"},
-    {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"},
-    {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"},
+    {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
+    {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
+    {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
 ]
 urllib3 = [
-    {file = "urllib3-1.26.5-py2.py3-none-any.whl", hash = "sha256:753a0374df26658f99d826cfe40394a686d05985786d946fbe4165b5148f5a7c"},
-    {file = "urllib3-1.26.5.tar.gz", hash = "sha256:a7acd0977125325f516bda9735fa7142b909a8d01e8b2e4c8108d0984e6e0098"},
+    {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"},
+    {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"},
 ]
 wrapt = [
     {file = "wrapt-1.12.1.tar.gz", hash = "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7"},
 ]
 zipp = [
-    {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"},
-    {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"},
+    {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
+    {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index cd69874..154b749 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -23,6 +23,7 @@ pylint = "^2.9.4"
 pytest = "^6.2.4"
 pytest-cov = "^2.12.1"
 coveralls = "^3.2.0"
+flake8 = "^3.9.2"
 
 [build-system]
 requires = ["poetry-core>=1.0.0"]
diff --git a/sql_metadata/__init__.py b/sql_metadata/__init__.py
index 04dfa81..93ed520 100644
--- a/sql_metadata/__init__.py
+++ b/sql_metadata/__init__.py
@@ -1,5 +1,6 @@
 """
-Module for parsing sql queries and returning columns, tables, names of with statements etc.
+Module for parsing sql queries and returning columns,
+tables, names of with statements etc.
 """
 # pylint:disable=unsubscriptable-object
 from sql_metadata.parser import Parser
diff --git a/sql_metadata/compat.py b/sql_metadata/compat.py
index f7675e1..5b1ded5 100644
--- a/sql_metadata/compat.py
+++ b/sql_metadata/compat.py
@@ -1,5 +1,6 @@
 """
-This module provides a temporary compatibility layer for legacy API dating back to 1.x version.
+This module provides a temporary compatibility layer
+for legacy API dating back to 1.x version.
 
 Change your old imports:
 
diff --git a/sql_metadata/generalizator.py b/sql_metadata/generalizator.py
index faf220f..5cdb093 100644
--- a/sql_metadata/generalizator.py
+++ b/sql_metadata/generalizator.py
@@ -53,7 +53,8 @@ class Generalizator:
     @property
     def generalize(self) -> str:
         """
-        Removes most variables from an SQL query and replaces them with X or N for numbers.
+        Removes most variables from an SQL query
+        and replaces them with X or N for numbers.
 
         Based on Mediawiki's DatabaseBase::generalizeSQL
         """
diff --git a/sql_metadata/keywords_lists.py b/sql_metadata/keywords_lists.py
index a535256..a010464 100644
--- a/sql_metadata/keywords_lists.py
+++ b/sql_metadata/keywords_lists.py
@@ -66,6 +66,20 @@ class QueryType(str, Enum):
     ALTER = "ALTER TABLE"
 
 
+class TokenType(str, Enum):
+    """
+    Types of SQLTokens
+    """
+
+    COLUMN = "COLUMN"
+    TABLE = "TABLE"
+    COLUMN_ALIAS = "COLUMN_ALIAS"
+    TABLE_ALIAS = "TABLE_ALIAS"
+    WITH_NAME = "WITH_NAME"
+    SUB_QUERY_NAME = "SUB_QUERY_NAME"
+    PARENTHESIS = "PARENTHESIS"
+
+
 # cannot fully replace with enum as with/select has the same key
 SUPPORTED_QUERY_TYPES = {
     "INSERT": QueryType.INSERT,
diff --git a/sql_metadata/parser.py b/sql_metadata/parser.py
index 2258184..34dc5ec 100644
--- a/sql_metadata/parser.py
+++ b/sql_metadata/parser.py
@@ -15,6 +15,7 @@ from sql_metadata.keywords_lists import (
     COLUMNS_SECTIONS,
     KEYWORDS_BEFORE_COLUMNS,
     QueryType,
+    TokenType,
     RELEVANT_KEYWORDS,
     SUBQUERY_PRECEDING_KEYWORDS,
     SUPPORTED_QUERY_TYPES,
@@ -73,6 +74,8 @@ class Parser:  # pylint: disable=R0902
         self._column_aliases_max_subquery_level = dict()
 
         self.sqlparse_tokens = None
+        self.non_empty_tokens = None
+        self.tokens_length = None
 
     @property
     def query(self) -> str:
@@ -124,34 +127,38 @@ class Parser:  # pylint: disable=R0902
         # handle empty queries (#12)
         if not parsed:
             return tokens
-
-        self.sqlparse_tokens = parsed[0].tokens
-        sqlparse_tokens = self._flatten_sqlparse()
-        non_empty_tokens = [
-            token
-            for token in sqlparse_tokens
-            if token.ttype is not Whitespace and token.ttype.parent is not Whitespace
-        ]
+        self._get_sqlparse_tokens(parsed)
         last_keyword = None
-        for index, tok in enumerate(non_empty_tokens):
+        combine_flag = False
+        for index, tok in enumerate(self.non_empty_tokens):
+            # combine dot separated identifiers
+            if self._is_token_part_of_complex_identifier(token=tok, index=index):
+                combine_flag = True
+                continue
             token = SQLToken(
                 tok=tok,
                 index=index,
                 subquery_level=self._subquery_level,
                 last_keyword=last_keyword,
             )
-            if index > 0:
-                # create links between consecutive tokens
-                token.previous_token = tokens[index - 1]
-                tokens[index - 1].next_token = token
+            if combine_flag:
+                self._combine_qualified_names(index=index, token=token)
+                combine_flag = False
+
+            previous_token = tokens[-1] if index > 0 else EmptyToken
+            token.previous_token = previous_token
+            previous_token.next_token = token if index > 0 else None
 
             if token.is_left_parenthesis:
+                token.token_type = TokenType.PARENTHESIS
                 self._determine_opening_parenthesis_type(token=token)
             elif token.is_right_parenthesis:
+                token.token_type = TokenType.PARENTHESIS
                 self._determine_closing_parenthesis_type(token=token)
 
-            if tok.is_keyword and "".join(tok.normalized.split()) in RELEVANT_KEYWORDS:
-                last_keyword = tok.normalized
+            last_keyword = self._determine_last_relevant_keyword(
+                token=token, last_keyword=last_keyword
+            )
             token.is_in_nested_function = self._is_in_nested_function
             token.parenthesis_level = self._parenthesis_level
             tokens.append(token)
@@ -176,7 +183,7 @@ class Parser:  # pylint: disable=R0902
         subqueries_names = self.subqueries_names
         with_names = self.with_names
 
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             # handle CREATE TABLE queries (#35)
             if token.is_name and self.query_type == QueryType.CREATE:
                 # previous token is either ( or , -> indicates the column name
@@ -185,11 +192,12 @@ class Parser:  # pylint: disable=R0902
                     and token.previous_token.is_punctuation
                     and token.last_keyword_normalized == "TABLE"
                 ):
+                    token.token_type = TokenType.COLUMN
                     columns.append(token.value)
                     continue
 
                 # we're in CREATE TABLE query with the columns
-                # ignore any annotations outside the parenthesis with the list of columns
+                # ignore annotations outside the parenthesis with the list of columns
                 # e.g. ) CHARACTER SET utf8;
                 if (
                     not token.is_in_parenthesis
@@ -198,16 +206,14 @@ class Parser:  # pylint: disable=R0902
                 ):
                     continue
 
-            if (
-                token.is_name and not token.next_token.is_dot
-            ) or token.is_keyword_column_name:
+            if token.is_name or token.is_keyword_column_name:
                 # analyze the name tokens, column names and where condition values
                 if (
                     token.last_keyword_normalized in KEYWORDS_BEFORE_COLUMNS
                     and token.previous_token.normalized not in ["AS", ")"]
                     and not token.is_alias_without_as
                     and (
-                        token.left_expanded not in self.columns_aliases_names
+                        token.value not in self.columns_aliases_names
                         or token.token_is_alias_of_self_not_from_subquery(
                             aliases_levels=self._column_aliases_max_subquery_level
                         )
@@ -234,12 +240,14 @@ class Parser:  # pylint: disable=R0902
                             self._add_to_columns_aliases_subsection(
                                 token=token, left_expand=False
                             )
+                            token.token_type = TokenType.COLUMN_ALIAS
                             continue
                         column = self._resolve_sub_queries(column)
                         self._add_to_columns_with_tables(token, column)
                         self._add_to_columns_subsection(
                             keyword=token.last_keyword_normalized, column=column
                         )
+                        token.token_type = TokenType.COLUMN
                         columns.extend(column)
 
                 elif (
@@ -251,9 +259,8 @@ class Parser:  # pylint: disable=R0902
                     self._add_to_columns_subsection(
                         keyword=token.last_keyword_normalized, column=column
                     )
+                    token.token_type = TokenType.COLUMN
                     columns.append(column)
-                elif token.left_expanded in self.columns_aliases_names:
-                    self._add_to_columns_aliases_subsection(token=token)
             elif (
                 token.is_wildcard
                 and token.last_keyword_normalized == "SELECT"
@@ -266,6 +273,7 @@ class Parser:  # pylint: disable=R0902
                 self._add_to_columns_subsection(
                     keyword=token.last_keyword_normalized, column=column
                 )
+                token.token_type = TokenType.COLUMN
                 columns.extend(column)
 
         self._columns = columns
@@ -331,7 +339,7 @@ class Parser:  # pylint: disable=R0902
                         alias_token = start_token.next_token.find_nearest_token(
                             self._aliases_to_check,
                             direction="right",
-                            value_attribute="left_expanded",
+                            value_attribute="value",
                         )
                         alias_of = self._resolve_alias_to_column(alias_token)
                     else:
@@ -359,7 +367,7 @@ class Parser:  # pylint: disable=R0902
                     )
                 if token.value != alias_of:
                     # skip aliases of self, like sum(column) as column
-                    column_aliases[token.left_expanded] = alias_of
+                    column_aliases[token.value] = alias_of
 
         self._columns_aliases = column_aliases
         return self._columns_aliases
@@ -387,18 +395,32 @@ class Parser:  # pylint: disable=R0902
         column_aliases_names = UniqueList()
         with_names = self.with_names
         subqueries_names = self.subqueries_names
-        for token in self.tokens:
-            if (
-                token.is_name
-                or (token.is_keyword and token.previous_token.normalized == "AS")
-            ) and not token.next_token.is_dot:
+        for token in self._not_parsed_tokens:
+            if token.is_name or (
+                token.is_keyword
+                and token.previous_token.normalized == "AS"
+                and token.last_keyword_normalized == "SELECT"
+            ):
+                if token.value in column_aliases_names:
+                    token.token_type = TokenType.COLUMN_ALIAS
+                    self._add_to_columns_aliases_subsection(token=token)
+                    current_level = self._column_aliases_max_subquery_level.get(
+                        token.value
+                    )
+                    if token.subquery_level > current_level:
+                        self._column_aliases_max_subquery_level[
+                            token.value
+                        ] = token.subquery_level
+                    continue
                 if (
                     token.last_keyword_normalized in KEYWORDS_BEFORE_COLUMNS
                     and token.normalized not in ["DIV"]
                     and token.is_alias_definition
                     or token.is_in_with_columns
                 ) and token.value not in with_names + subqueries_names:
-                    alias = token.left_expanded
+                    alias = token.value
+                    token.token_type = TokenType.COLUMN_ALIAS
+                    self._add_to_columns_aliases_subsection(token=token)
                     column_aliases_names.append(alias)
                     current_level = self._column_aliases_max_subquery_level.setdefault(
                         alias, 0
@@ -421,7 +443,7 @@ class Parser:  # pylint: disable=R0902
         tables = UniqueList()
         with_names = self.with_names
 
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             if (
                 (token.is_name or token.is_keyword)
                 and token.last_keyword_normalized in TABLE_ADJUSTMENT_KEYWORDS
@@ -443,17 +465,13 @@ class Parser:  # pylint: disable=R0902
                 ):
                     continue
 
-                if token.next_token.is_dot:
-                    pass  # part of the qualified name
-                elif token.is_in_parenthesis and (
+                if token.is_in_parenthesis and (
                     token.find_nearest_token("(").previous_token.value in with_names
                     or token.last_keyword_normalized == "INTO"
                 ):
                     # we are in <columns> of INSERT INTO <TABLE> (<columns>)
                     # or columns of with statement: with (<columns>) as ...
                     pass
-                elif token.previous_token.is_dot:
-                    tables.append(token.left_expanded)  # full qualified name
                 elif (
                     token.previous_token.normalized != token.last_keyword_normalized
                     and not token.previous_token.is_punctuation
@@ -465,6 +483,7 @@ class Parser:  # pylint: disable=R0902
                     pass
                 else:
                     table_name = str(token.value.strip("`"))
+                    token.token_type = TokenType.TABLE
                     tables.append(table_name)
 
         self._tables = tables - with_names
@@ -480,7 +499,7 @@ class Parser:  # pylint: disable=R0902
         limit = None
         offset = None
 
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             if token.is_integer:
                 if token.last_keyword_normalized == "LIMIT" and not limit:
                     # LIMIT <limit>
@@ -512,21 +531,21 @@ class Parser:  # pylint: disable=R0902
         aliases = dict()
         tables = self.tables
 
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             if (
                 token.last_keyword_normalized in TABLE_ADJUSTMENT_KEYWORDS
                 and token.is_name
                 and token.next_token.normalized != "AS"
-                and not token.next_token.is_dot
             ):
                 if token.previous_token.normalized == "AS":
                     # potential <DB.<SCHEMA>.<TABLE> as <ALIAS>
-                    potential_table_name = token.get_nth_previous(2).left_expanded
+                    potential_table_name = token.get_nth_previous(2).value
                 else:
                     # potential <DB.<SCHEMA>.<TABLE> <ALIAS>
-                    potential_table_name = token.previous_token.left_expanded
+                    potential_table_name = token.previous_token.value
 
                 if potential_table_name in tables:
+                    token.token_type = TokenType.TABLE_ALIAS
                     aliases[token.value] = potential_table_name
 
         self._table_aliases = aliases
@@ -545,7 +564,7 @@ class Parser:  # pylint: disable=R0902
         if self._with_names is not None:
             return self._with_names
         with_names = UniqueList()
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             if token.previous_token.normalized == "WITH":
                 self._is_in_with_block = True
                 while self._is_in_with_block and token.next_token:
@@ -560,9 +579,11 @@ class Parser:  # pylint: disable=R0902
                             start_token.is_with_columns_start = True
                             start_token.is_nested_function_start = False
                             prev_token = start_token.previous_token
-                            with_names.append(prev_token.left_expanded)
+                            prev_token.token_type = TokenType.WITH_NAME
+                            with_names.append(prev_token.value)
                         else:
-                            with_names.append(token.left_expanded)
+                            token.token_type = TokenType.WITH_NAME
+                            with_names.append(token.value)
                         # move to next with query end
                         while token.next_token and not token.is_with_query_end:
                             token = token.next_token
@@ -591,7 +612,7 @@ class Parser:  # pylint: disable=R0902
         with_queries_columns = dict()
         for name in self.with_names:
             token = self.tokens[0].find_nearest_token(
-                name, value_attribute="left_expanded", direction="right"
+                name, value_attribute="value", direction="right"
             )
             if token.next_token.is_with_columns_start:
                 with_queries_columns[name] = True
@@ -665,6 +686,7 @@ class Parser:  # pylint: disable=R0902
                 token.previous_token.normalized == "AS"
                 and token.get_nth_previous(2).is_subquery_end
             ):
+                token.token_type = TokenType.SUB_QUERY_NAME
                 subqueries_names.append(str(token))
 
         self._subqueries_names = subqueries_names
@@ -678,7 +700,7 @@ class Parser:  # pylint: disable=R0902
         if self._values:
             return self._values
         values = []
-        for token in self.tokens:
+        for token in self._not_parsed_tokens:
             if (
                 token.last_keyword_normalized == "VALUES"
                 and token.is_in_parenthesis
@@ -734,6 +756,13 @@ class Parser:  # pylint: disable=R0902
         """
         return Generalizator(self._raw_query).generalize
 
+    @property
+    def _not_parsed_tokens(self):
+        """
+        Returns only tokens that have no type assigned yet
+        """
+        return [x for x in self.tokens if x.token_type is None]
+
     def _add_to_columns_subsection(self, keyword: str, column: Union[str, List[str]]):
         """
         Add columns to the section in which it appears in query
@@ -753,7 +782,7 @@ class Parser:  # pylint: disable=R0902
         Add alias to the section in which it appears in query
         """
         keyword = token.last_keyword_normalized
-        alias = token.left_expanded if left_expand else token.value
+        alias = token.value if left_expand else token.value.split(".")[-1]
         if (
             token.last_keyword_normalized in ["FROM", "WITH"]
             and token.find_nearest_token("(").is_with_columns_start
@@ -768,7 +797,7 @@ class Parser:  # pylint: disable=R0902
     ) -> None:
         if isinstance(column, list) and len(column) == 1:
             column = column[0]
-        self._columns_with_tables_aliases[token.left_expanded] = column
+        self._columns_with_tables_aliases[token.value] = column
 
     def _resolve_column_alias(self, alias: Union[str, List[str]]) -> Union[str, List]:
         """
@@ -786,10 +815,10 @@ class Parser:  # pylint: disable=R0902
         """
         Resolves aliases of tables to already resolved columns
         """
-        if alias_token.left_expanded in self._columns_with_tables_aliases:
-            alias_of = self._columns_with_tables_aliases[alias_token.left_expanded]
+        if alias_token.value in self._columns_with_tables_aliases:
+            alias_of = self._columns_with_tables_aliases[alias_token.value]
         else:
-            alias_of = alias_token.left_expanded
+            alias_of = alias_token.value
         return alias_of
 
     def _resolve_sub_queries(self, column: str) -> List[str]:
@@ -862,7 +891,7 @@ class Parser:  # pylint: disable=R0902
         parts = col_alias.split(".")
         if len(parts) != 2 or parts[0] not in self.with_names:
             return False
-        if self._with_queries_columns[parts[0]]:
+        if self._with_queries_columns.get(parts[0]):
             return True
         return False
 
@@ -941,7 +970,7 @@ class Parser:  # pylint: disable=R0902
         loop_token = start_token
         aliases = UniqueList()
         while loop_token.next_token != end_token:
-            if loop_token.next_token.left_expanded in self._aliases_to_check:
+            if loop_token.next_token.value in self._aliases_to_check:
                 alias_token = loop_token.next_token
                 if (
                     alias_token.normalized != "*"
@@ -979,6 +1008,53 @@ class Parser:  # pylint: disable=R0902
 
         return query
 
+    @staticmethod
+    def _determine_last_relevant_keyword(token: SQLToken, last_keyword: str):
+        if token.is_keyword and "".join(token.normalized.split()) in RELEVANT_KEYWORDS:
+            if not (
+                token.normalized == "FROM"
+                and token.get_nth_previous(3).normalized == "EXTRACT"
+            ):
+                last_keyword = token.normalized
+        return last_keyword
+
+    def _is_token_part_of_complex_identifier(
+        self, token: sqlparse.tokens.Token, index: int
+    ) -> bool:
+        """
+        Checks if token is a part of complex identifier like
+        <schema>.<table>.<column> or <table/sub_query>.<column>
+        """
+        return str(token) == "." or (
+            index + 1 < self.tokens_length
+            and str(self.non_empty_tokens[index + 1]) == "."
+        )
+
+    def _combine_qualified_names(self, index: int, token: SQLToken) -> None:
+        """
+        Combines names like <schema>.<table>.<column> or <table/sub_query>.<column>
+        """
+        value = token.value
+        prev_value = self.non_empty_tokens[index - 2].value.strip("`").strip('"')
+        value = f"{prev_value}.{value}"
+        if index >= 3 and str(self.non_empty_tokens[index - 3]) == ".":
+            prev_value = self.non_empty_tokens[index - 4].value.strip("`").strip('"')
+            value = f"{prev_value}.{value}"
+        token.value = value
+
+    def _get_sqlparse_tokens(self, parsed) -> None:
+        """
+        Flattens the tokens and removes whitespace
+        """
+        self.sqlparse_tokens = parsed[0].tokens
+        sqlparse_tokens = self._flatten_sqlparse()
+        self.non_empty_tokens = [
+            token
+            for token in sqlparse_tokens
+            if token.ttype is not Whitespace and token.ttype.parent is not Whitespace
+        ]
+        self.tokens_length = len(self.non_empty_tokens)
+
     def _flatten_sqlparse(self):
         for token in self.sqlparse_tokens:
             # sqlparse returns mysql digit starting identifiers as group
diff --git a/sql_metadata/token.py b/sql_metadata/token.py
index 951814e..01ee236 100644
--- a/sql_metadata/token.py
+++ b/sql_metadata/token.py
@@ -43,6 +43,7 @@ class SQLToken:  # pylint: disable=R0902
             self.next_token = EmptyToken
             self.previous_token = EmptyToken
             self.subquery_level = subquery_level
+        self.token_type = None
 
         self._set_default_parenthesis_status()
 
@@ -129,20 +130,6 @@ class SQLToken:  # pylint: disable=R0902
             return self.last_keyword.translate(str.maketrans("", "", " \n\t\r")).upper()
         return ""
 
-    @property
-    def left_expanded(self) -> str:
-        """
-        Property tries to expand value with dot notation if left token is a dot
-        to capture whole groups like <SCHEMA>.<TABLE> or <DATABASE>.<SCHEMA>.<TABLE>
-        """
-        value = str(self)
-        token = self
-        while token.previous_token and token.previous_token.is_dot:
-            if token.get_nth_previous(2) and token.get_nth_previous(2).is_name:
-                value = f"{token.get_nth_previous(2)}." + value
-            token = token.get_nth_previous(2)
-        return value.strip("`")
-
     @property
     def is_in_parenthesis(self) -> bool:
         """
@@ -191,6 +178,7 @@ class SQLToken:  # pylint: disable=R0902
         return (
             self.next_token.normalized in [",", "FROM"]
             and self.previous_token.normalized not in [",", ".", "(", "SELECT"]
+            and not self.previous_token.is_keyword
             and (
                 self.last_keyword_normalized == "SELECT"
                 or self.previous_token.is_column_definition_end
@@ -269,7 +257,7 @@ class SQLToken:  # pylint: disable=R0902
         """
         Substitutes table alias with actual table name
         """
-        value = self.left_expanded
+        value = self.value
         if "." in value:
             parts = value.split(".")
             if len(parts) > 2:  # pragma: no cover


Test patch:
diff --git a/test/test_aliases.py b/test/test_aliases.py
index 90ee5d4..a980992 100644
--- a/test/test_aliases.py
+++ b/test/test_aliases.py
@@ -13,7 +13,8 @@ def test_get_query_table_aliases():
         Parser("SELECT e.foo FROM (SELECT * FROM bar) AS e").tables_aliases == {}
     ), "Sub-query aliases are ignored"
     assert Parser(
-        "SELECT a.* FROM product_a AS a JOIN product_b AS b ON a.ip_address = b.ip_address"
+        "SELECT a.* FROM product_a AS a "
+        "JOIN product_b AS b ON a.ip_address = b.ip_address"
     ).tables_aliases == {"a": "product_a", "b": "product_b"}
 
 
diff --git a/test/test_column_aliases.py b/test/test_column_aliases.py
index 934c0f2..8724d11 100644
--- a/test/test_column_aliases.py
+++ b/test/test_column_aliases.py
@@ -6,9 +6,11 @@ def test_column_aliases_with_subquery():
     SELECT yearweek(SignDate) as                         Aggregation,
        BusinessSource,
        (SELECT sum(C2Count)
-        from (SELECT count(C2) as C2Count, BusinessSource, yearweek(Start1) Start1, yearweek(End1) End1
+        from (SELECT count(C2) as C2Count, BusinessSource,
+        yearweek(Start1) Start1, yearweek(End1) End1
               from (
-                       SELECT ContractID as C2, BusinessSource, StartDate as Start1, EndDate as End1
+                       SELECT ContractID as C2, BusinessSource, StartDate as Start1,
+                       EndDate as End1
                        from data_contracts_report
                    ) sq2
               group by 2, 3, 4) sq
diff --git a/test/test_comments.py b/test/test_comments.py
index d9d5a20..1fe71c9 100644
--- a/test/test_comments.py
+++ b/test/test_comments.py
@@ -3,13 +3,16 @@ from sql_metadata import Parser
 
 def test_getting_comments():
     parser = Parser(
-        "INSERT /* VoteHelper::addVote xxx */  INTO `page_vote` (article_id,user_id,`time`) VALUES ('442001','27574631','20180228130846')"
+        "INSERT /* VoteHelper::addVote xxx */  "
+        "INTO `page_vote` (article_id,user_id,`time`) "
+        "VALUES ('442001','27574631','20180228130846')"
     )
     assert parser.comments == ["/* VoteHelper::addVote xxx */"]
 
     parser = Parser(
         "SELECT /* CategoryPaginationViewer::processSection */  "
-        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  FROM `page` "
+        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  "
+        "FROM `page` "
         "INNER JOIN `categorylinks` FORCE INDEX (cl_sortkey) ON ((cl_from = page_id))  "
         " /* We should add more conditions */ "
         "WHERE cl_type = 'page' AND cl_to = 'Spotify/Song'  "
diff --git a/test/test_create_table.py b/test/test_create_table.py
index 9f57446..4132d56 100644
--- a/test/test_create_table.py
+++ b/test/test_create_table.py
@@ -49,7 +49,7 @@ def test_simple_create_table_as_select():
 
 def test_create_table_as_select_with_joins():
     qry = """
-        CREATE table xyz as 
+        CREATE table xyz as
         SELECT *
         from table_a
         join table_b on (table_a.name = table_b.name)
@@ -70,7 +70,7 @@ def test_create_table_as_select_with_joins():
 
 def test_creating_table_as_select_with_with_clause():
     qry = """
-        CREATE table xyz as 
+        CREATE table xyz as
         with sub as (select it_id from internal_table)
         SELECT *
         from table_a
@@ -109,7 +109,7 @@ def test_creating_table_as_select_with_with_clause():
 
 def test_create_table_as_select_in_parentheses():
     qry = """
-        CREATE TABLE records AS 
+        CREATE TABLE records AS
         (SELECT t.id, t.name, e.name as energy FROM t JOIN e ON t.e_id = e.id)
         """
     parser = Parser(qry)
@@ -133,7 +133,7 @@ def test_create_table_with_schema_name():
 
 def test_create_table_as_select_in_parentheses_with_schema():
     qry = """
-        CREATE TABLE mysuper_secret_schema.records AS 
+        CREATE TABLE mysuper_secret_schema.records AS
         (SELECT t.id, t.name, e.name as energy FROM t JOIN e ON t.e_id = e.id)
         """
     parser = Parser(qry)
diff --git a/test/test_getting_columns.py b/test/test_getting_columns.py
index f35c022..2297f28 100644
--- a/test/test_getting_columns.py
+++ b/test/test_getting_columns.py
@@ -15,7 +15,8 @@ def test_cast_and_convert_functions():
 
 def test_queries_with_null_conditions():
     parser = Parser(
-        "SELECT id FROM cm WHERE cm.status = 1 AND cm.OPERATIONDATE IS NULL AND cm.OID IN(123123);"
+        "SELECT id FROM cm WHERE cm.status = 1 AND cm.OPERATIONDATE IS NULL "
+        "AND cm.OID IN(123123);"
     )
     assert parser.columns == ["id", "cm.status", "cm.OPERATIONDATE", "cm.OID"]
     assert parser.columns_dict == {
@@ -24,7 +25,8 @@ def test_queries_with_null_conditions():
     }
 
     parser = Parser(
-        "SELECT id FROM cm WHERE cm.status = 1 AND cm.OPERATIONDATE IS NOT NULL AND cm.OID IN(123123);"
+        "SELECT id FROM cm WHERE cm.status = 1 AND cm.OPERATIONDATE IS NOT NULL "
+        "AND cm.OID IN(123123);"
     )
     assert parser.columns == ["id", "cm.status", "cm.OPERATIONDATE", "cm.OID"]
     assert parser.columns_dict == {
@@ -40,7 +42,7 @@ def test_queries_with_distinct():
 
 
 def test_joins():
-    assert ["page_title", "rd_title", "rd_namespace", "page_id", "rd_from",] == Parser(
+    assert ["page_title", "rd_title", "rd_namespace", "page_id", "rd_from"] == Parser(
         "SELECT  page_title  FROM `redirect` INNER JOIN `page` "
         "ON (rd_title = 'foo' AND rd_namespace = '100' AND (page_id = rd_from))"
     ).columns
@@ -106,7 +108,8 @@ def test_update_and_replace():
 
     # REPLACE queries
     parser = Parser(
-        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) VALUES ('47','infoboxes','')"
+        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) "
+        "VALUES ('47','infoboxes','')"
     )
     assert parser.query_type == QueryType.REPLACE
     assert parser.columns == ["pp_page", "pp_propname", "pp_value"]
@@ -116,14 +119,18 @@ def test_update_and_replace():
 def test_complex_queries_columns():
     # @see https://github.com/macbre/sql-metadata/issues/6
     assert Parser(
-        "SELECT 1 as c    FROM foo_pageviews WHERE time_id = '2018-01-07 00:00:00' AND period_id = '2' LIMIT 1"
+        "SELECT 1 as c    FROM foo_pageviews WHERE time_id = '2018-01-07 00:00:00' "
+        "AND period_id = '2' LIMIT 1"
     ).columns == ["time_id", "period_id"]
 
     # table aliases
     parser = Parser(
-        "SELECT r.wiki_id AS id, pageviews_7day AS pageviews FROM report_wiki_recent_pageviews AS r "
-        "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id WHERE d.is_public = '1' "
-        "AND r.lang IN ( 'en', 'ru' ) AND r.hub_name = 'gaming' ORDER BY pageviews DESC LIMIT 300"
+        "SELECT r.wiki_id AS id, pageviews_7day AS pageviews "
+        "FROM report_wiki_recent_pageviews AS r "
+        "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id "
+        "WHERE d.is_public = '1' "
+        "AND r.lang IN ( 'en', 'ru' ) AND r.hub_name = 'gaming' "
+        "ORDER BY pageviews DESC LIMIT 300"
     )
     assert parser.columns_aliases_names == ["id", "pageviews"]
     assert parser.columns_aliases == {
@@ -162,7 +169,8 @@ def test_complex_queries_columns():
         "SELECT  count(fw1.wiki_id) as wam_results_total  FROM `fact_wam_scores` `fw1` "
         "left join `fact_wam_scores` `fw2` ON ((fw1.wiki_id = fw2.wiki_id) AND "
         "(fw2.time_id = FROM_UNIXTIME(1466380800))) left join `dimension_wikis` `dw` "
-        "ON ((fw1.wiki_id = dw.wiki_id))  WHERE (fw1.time_id = FROM_UNIXTIME(1466467200)) "
+        "ON ((fw1.wiki_id = dw.wiki_id))  "
+        "WHERE (fw1.time_id = FROM_UNIXTIME(1466467200)) "
         "AND (dw.url like '%%' OR dw.title like '%%') AND fw1.vertical_id IN "
         "('0','1','2','3','4','5','6','7')  AND (fw1.wiki_id NOT "
         "IN ('23312','70256','168929','463633','381622','1089624')) "
@@ -200,14 +208,17 @@ def test_complex_queries_columns():
 
 def test_columns_with_comments():
     parser = Parser(
-        "INSERT /* VoteHelper::addVote xxx */  INTO `page_vote` (article_id,user_id,`time`) VALUES ('442001','27574631','20180228130846')"
+        "INSERT /* VoteHelper::addVote xxx */  "
+        "INTO `page_vote` (article_id,user_id,`time`) "
+        "VALUES ('442001','27574631','20180228130846')"
     )
     assert parser.query_type == QueryType.INSERT
     assert parser.columns == ["article_id", "user_id", "time"]
 
     # REPLACE queries
     parser = Parser(
-        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) VALUES ('47','infoboxes','')"
+        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) "
+        "VALUES ('47','infoboxes','')"
     )
     assert parser.query_type == QueryType.REPLACE
     assert parser.columns == ["pp_page", "pp_propname", "pp_value"]
@@ -215,7 +226,8 @@ def test_columns_with_comments():
 
     assert Parser(
         "SELECT /* CategoryPaginationViewer::processSection */  "
-        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  FROM `page` "
+        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  "
+        "FROM `page` "
         "INNER JOIN `categorylinks` FORCE INDEX (cl_sortkey) ON ((cl_from = page_id))  "
         "WHERE cl_type = 'page' AND cl_to = 'Spotify/Song'  "
         "ORDER BY cl_sortkey LIMIT 927600,200"
@@ -235,7 +247,12 @@ def test_columns_with_comments():
 
 def test_columns_with_keyword_aliases():
     parser = Parser(
-        "SELECT date_format(time_id,'%Y-%m-%d') AS date, pageviews AS cnt         FROM rollup_wiki_pageviews      WHERE period_id = '2'   AND wiki_id = '1676379'         AND time_id BETWEEN '2018-01-08'        AND '2018-01-01'"
+        "SELECT date_format(time_id,'%Y-%m-%d') AS date, pageviews AS cnt         "
+        "FROM rollup_wiki_pageviews      "
+        "WHERE period_id = '2'   "
+        "AND wiki_id = '1676379'         "
+        "AND time_id BETWEEN '2018-01-08'        "
+        "AND '2018-01-01'"
     )
     assert parser.columns == ["time_id", "pageviews", "period_id", "wiki_id"]
     assert parser.columns_aliases_names == ["date", "cnt"]
@@ -252,14 +269,15 @@ def test_columns_and_sql_functions():
     ]
     assert Parser("SELECT avg(col)+sum(col2) from dual").columns == ["col", "col2"]
     assert Parser(
-        "SELECT count(col)+max(col2)+ min(col3)+ count(distinct  col4) + custom_func(col5) from dual"
+        "SELECT count(col)+max(col2)+ min(col3)+ count(distinct  col4) + "
+        "custom_func(col5) from dual"
     ).columns == ["col", "col2", "col3", "col4", "col5"]
 
 
 def test_columns_starting_with_keywords():
     query = """
-    SELECT `schema_name`, full_table_name, `column_name`, `catalog_name`, 
-    `table_name`, column_length, column_weight, annotation 
+    SELECT `schema_name`, full_table_name, `column_name`, `catalog_name`,
+    `table_name`, column_length, column_weight, annotation
     FROM corporate.all_tables
     """
     parser = Parser(query)
@@ -277,8 +295,8 @@ def test_columns_starting_with_keywords():
 
 def test_columns_as_unquoted_keywords():
     query = """
-    SELECT schema_name, full_table_name, column_name, catalog_name, 
-    table_name, column_length, column_weight, annotation 
+    SELECT schema_name, full_table_name, column_name, catalog_name,
+    table_name, column_length, column_weight, annotation
     FROM corporate.all_tables
     """
     parser = Parser(query)
@@ -310,25 +328,25 @@ def test_columns_with_keywords_parts():
 
 def test_columns_with_complex_aliases_same_as_columns():
     query = """
-    SELECT targetingtype, sellerid, sguid, 'd01' as datetype, adgroupname, targeting, 
-    customersearchterm, 
-    'product_search_term' as `type`, 
-    sum(impressions) as impr, 
-    sum(clicks) as clicks, 
-    sum(seventotalunits) as sold, 
-    sum(sevenadvertisedskuunits) as advertisedskuunits, 
-    sum(sevenotherskuunits) as otherskuunits, 
-    sum(sevendaytotalsales) as totalsales, 
-    round(sum(spend), 4) as spend, if(sum(impressions) > 0, 
-    round(sum(clicks)/sum(impressions), 4), 0) as ctr, 
-    if(sum(clicks) > 0, round(sum(seventotalunits)/sum(clicks), 4), 0) as cr, 
-    if(sum(clicks) > 0, round(sum(spend)/sum(clicks), 2), 0) as cpc 
-    from amazon_pl.search_term_report_impala 
-    where reportday >= to_date('2021-05-16 00:00:00.0') 
-    and reportday <= to_date('2021-05-16 00:00:00.0') 
-    and targetingtype in ('auto','manual') 
-    and sguid is not null and sguid != '' 
-    group by targetingtype,sellerid,sguid,adgroupname,targeting,customersearchterm 
+    SELECT targetingtype, sellerid, sguid, 'd01' as datetype, adgroupname, targeting,
+    customersearchterm,
+    'product_search_term' as `type`,
+    sum(impressions) as impr,
+    sum(clicks) as clicks,
+    sum(seventotalunits) as sold,
+    sum(sevenadvertisedskuunits) as advertisedskuunits,
+    sum(sevenotherskuunits) as otherskuunits,
+    sum(sevendaytotalsales) as totalsales,
+    round(sum(spend), 4) as spend, if(sum(impressions) > 0,
+    round(sum(clicks)/sum(impressions), 4), 0) as ctr,
+    if(sum(clicks) > 0, round(sum(seventotalunits)/sum(clicks), 4), 0) as cr,
+    if(sum(clicks) > 0, round(sum(spend)/sum(clicks), 2), 0) as cpc
+    from amazon_pl.search_term_report_impala
+    where reportday >= to_date('2021-05-16 00:00:00.0')
+    and reportday <= to_date('2021-05-16 00:00:00.0')
+    and targetingtype in ('auto','manual')
+    and sguid is not null and sguid != ''
+    group by targetingtype,sellerid,sguid,adgroupname,targeting,customersearchterm
     order by impr desc
     """
     parser = Parser(query)
@@ -353,11 +371,11 @@ def test_columns_with_complex_aliases_same_as_columns():
 def test_columns_aliases_as_unqoted_keywords():
     query = """
     SELECT
-    product_search_term as type, 
-    sum(clicks) as clicks, 
-    sum(seventotalunits) as schema_name, 
+    product_search_term as type,
+    sum(clicks) as clicks,
+    sum(seventotalunits) as schema_name,
     sum(sevenadvertisedskuunits) as advertisedskuunits
-    from amazon_pl.search_term_report_impala 
+    from amazon_pl.search_term_report_impala
     """
     parser = Parser(query)
     assert parser.columns == [
@@ -381,10 +399,10 @@ def test_columns_aliases_as_unqoted_keywords():
 
 def test_columns_with_aliases_same_as_columns():
     query = """
-    SELECT 
-    round(sum(impressions),1) as impressions, 
+    SELECT
+    round(sum(impressions),1) as impressions,
     sum(clicks) as clicks
-    from amazon_pl.search_term_report_impala 
+    from amazon_pl.search_term_report_impala
     """
     parser = Parser(query)
     assert parser.columns == ["impressions", "clicks"]
@@ -392,9 +410,9 @@ def test_columns_with_aliases_same_as_columns():
 
     query = """
     SELECT
-    if(sum(clicks) > 0, round(sum(seventotalunits)/sum(clicks), 4), 0) as clicks, 
-    if(sum(clicks) > 0, round(sum(spend)/sum(clicks), 2), 0) as cpc 
-    from amazon_pl.search_term_report_impala 
+    if(sum(clicks) > 0, round(sum(seventotalunits)/sum(clicks), 4), 0) as clicks,
+    if(sum(clicks) > 0, round(sum(spend)/sum(clicks), 2), 0) as cpc
+    from amazon_pl.search_term_report_impala
     """
     parser = Parser(query)
     assert parser.columns == ["clicks", "seventotalunits", "spend"]
@@ -402,3 +420,9 @@ def test_columns_with_aliases_same_as_columns():
         "clicks": ["clicks", "seventotalunits"],
         "cpc": ["clicks", "spend"],
     }
+
+
+def test_columns_with_distinct():
+    query = "SELECT DISTINCT customer_id FROM table"
+    parsed = Parser(query)
+    assert parsed.columns == ["customer_id"]
diff --git a/test/test_getting_tables.py b/test/test_getting_tables.py
index bdf40c9..b297e82 100644
--- a/test/test_getting_tables.py
+++ b/test/test_getting_tables.py
@@ -19,11 +19,19 @@ def test_simple_queries_tables():
     ).tables
 
     assert ["revision", "page", "wikicities_user"] == Parser(
-        "SELECT rev_id,rev_page,rev_text_id,rev_timestamp,rev_comment,rev_user_text,rev_user,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_shaN,page_namespace,page_title,page_id,page_latest,user_name FROM `revision` INNER JOIN `page` ON ((page_id = rev_page)) LEFT JOIN `wikicities_user` ON ((rev_user != N) AND (user_id = rev_user)) WHERE rev_id = X LIMIT N"
+        "SELECT rev_id,rev_page,rev_text_id,rev_timestamp,rev_comment,rev_user_text,"
+        "rev_user,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_shaN,"
+        "page_namespace,page_title,page_id,page_latest,user_name "
+        "FROM `revision` INNER JOIN `page` ON ((page_id = rev_page)) "
+        "LEFT JOIN `wikicities_user` ON ((rev_user != N) AND (user_id = rev_user)) "
+        "WHERE rev_id = X LIMIT N"
     ).tables
 
     assert ["events"] == Parser(
-        "SELECT COUNT( 0 ) AS cnt, date_format(event_date, '%Y-%m-%d') AS date 	 FROM events 	 WHERE event_date BETWEEN '2017-10-18 00:00:00' 	 AND '2017-10-24 23:59:59'  	 AND wiki_id = '1289985' GROUP BY date WITH ROLLUP"
+        "SELECT COUNT( 0 ) AS cnt, date_format(event_date, '%Y-%m-%d') AS date 	 "
+        "FROM events 	 WHERE event_date BETWEEN '2017-10-18 00:00:00' 	 "
+        "AND '2017-10-24 23:59:59'  	 "
+        "AND wiki_id = '1289985' GROUP BY date WITH ROLLUP"
     ).tables
 
 
@@ -31,36 +39,59 @@ def test_complex_query_tables():
     # complex queries
     # @see https://github.com/macbre/query-digest/issues/16
     assert ["report_wiki_recent_pageviews", "dimension_wikis"] == Parser(
-        "SELECT r.wiki_id AS id, pageviews_Nday AS pageviews FROM report_wiki_recent_pageviews AS r INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id WHERE d.public = X AND r.lang = X AND r.hub_name = X ORDER BY pageviews DESC LIMIT N"
+        "SELECT r.wiki_id AS id, pageviews_Nday AS pageviews "
+        "FROM report_wiki_recent_pageviews AS r "
+        "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id "
+        "WHERE d.public = X AND r.lang = X AND r.hub_name = X "
+        "ORDER BY pageviews DESC LIMIT N"
     ).tables
 
     assert ["dimension_wikis", "fact_wam_scores"] == Parser(
-        "SELECT DISTINCT dw.lang FROM `dimension_wikis` `dw` INNER JOIN `fact_wam_scores` `fwN` ON ((dw.wiki_id = fwN.wiki_id)) WHERE fwN.time_id = FROM_UNIXTIME(N) ORDER BY dw.lang ASC"
+        "SELECT DISTINCT dw.lang FROM `dimension_wikis` `dw` "
+        "INNER JOIN `fact_wam_scores` `fwN` ON ((dw.wiki_id = fwN.wiki_id)) "
+        "WHERE fwN.time_id = FROM_UNIXTIME(N) ORDER BY dw.lang ASC"
     ).tables
 
     assert ["fact_wam_scores", "dimension_wikis"] == Parser(
-        "SELECT count(fwN.wiki_id) as wam_results_total FROM `fact_wam_scores` `fwN` left join `fact_wam_scores` `fwN` ON ((fwN.wiki_id = fwN.wiki_id) AND (fwN.time_id = FROM_UNIXTIME(N))) left join `dimension_wikis` `dw` ON ((fwN.wiki_id = dw.wiki_id)) WHERE (fwN.time_id = FROM_UNIXTIME(N)) AND (dw.url like X OR dw.title like X) AND fwN.vertical_id IN (XYZ) AND dw.lang = X AND (fwN.wiki_id NOT IN (XYZ)) AND ((dw.url IS NOT NULL AND dw.title IS NOT NULL))"
+        "SELECT count(fwN.wiki_id) as wam_results_total FROM `fact_wam_scores` `fwN` "
+        "left join `fact_wam_scores` `fwN` ON ((fwN.wiki_id = fwN.wiki_id) "
+        "AND (fwN.time_id = FROM_UNIXTIME(N))) "
+        "left join `dimension_wikis` `dw` ON ((fwN.wiki_id = dw.wiki_id)) "
+        "WHERE (fwN.time_id = FROM_UNIXTIME(N)) AND (dw.url like X OR dw.title like X) "
+        "AND fwN.vertical_id IN (XYZ) AND dw.lang = X AND (fwN.wiki_id NOT IN (XYZ)) "
+        "AND ((dw.url IS NOT NULL AND dw.title IS NOT NULL))"
     ).tables
 
     assert ["revision", "page", "wikicities_cN.user"] == Parser(
-        "SELECT rev_id,rev_page,rev_text_id,rev_timestamp,rev_comment,rev_user_text,rev_user,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_shaN,page_namespace,page_title,page_id,page_latest,user_name FROM `revision` INNER JOIN `page` ON ((page_id = rev_page)) LEFT JOIN `wikicities_cN`.`user` ON ((rev_user != N) AND (user_id = rev_user)) WHERE rev_id = X LIMIT N"
+        "SELECT rev_id,rev_page,rev_text_id,rev_timestamp,rev_comment,rev_user_text,"
+        "rev_user,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_shaN,"
+        "page_namespace,page_title,page_id,page_latest,user_name "
+        "FROM `revision` INNER JOIN `page` ON ((page_id = rev_page)) "
+        "LEFT JOIN `wikicities_cN`.`user` ON ((rev_user != N) "
+        "AND (user_id = rev_user)) WHERE rev_id = X LIMIT N"
     ).tables
 
     # complex queries, take two
     # @see https://github.com/macbre/sql-metadata/issues/6
     assert ["foo_pageviews"] == Parser(
-        "SELECT 1 as c    FROM foo_pageviews      WHERE time_id = '2018-01-07 00:00:00'   AND period_id = '2' LIMIT 1"
+        "SELECT 1 as c    FROM foo_pageviews      "
+        "WHERE time_id = '2018-01-07 00:00:00'   AND period_id = '2' LIMIT 1"
     ).tables
 
     # table aliases
     assert ["report_wiki_recent_pageviews", "dimension_wikis"] == Parser(
-        "SELECT r.wiki_id AS id, pageviews_7day AS pageviews FROM report_wiki_recent_pageviews AS r INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id WHERE d.public = '1' AND r.lang IN ( 'en', 'ru' ) AND r.hub_name = 'gaming' ORDER BY pageviews DESC LIMIT 300"
+        "SELECT r.wiki_id AS id, pageviews_7day AS pageviews "
+        "FROM report_wiki_recent_pageviews AS r "
+        "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id "
+        "WHERE d.public = '1' AND r.lang IN ( 'en', 'ru' ) "
+        "AND r.hub_name = 'gaming' ORDER BY pageviews DESC LIMIT 300"
     ).tables
 
     # include multiple FROM tables when they prefixed
     # @see https://github.com/macbre/sql-metadata/issues/38
     assert ["MYDB1.TABLE1", "MYDB2.TABLE2"] == Parser(
-        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY FROM MYDB1.TABLE1 AS A, MYDB2.TABLE2 AS B"
+        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY "
+        "FROM MYDB1.TABLE1 AS A, MYDB2.TABLE2 AS B"
     ).tables
 
     # test whitespaces in keywords
@@ -68,7 +99,8 @@ def test_complex_query_tables():
     assert (
         ["tab", "tab2"]
         == Parser(
-            """SELECT a,b,c from tab full  outer \r\n\t  join tab2  on (col1 = col2) group   
+            """SELECT a,b,c from tab
+            full  outer \r\n\t  join tab2  on (col1 = col2) group
 \r\n   \t   by  a, b, c """
         ).tables
     )
@@ -77,16 +109,34 @@ def test_complex_query_tables():
 def test_joins():
     # self joins
     assert ["fact_wam_scores", "dimension_wikis"] == Parser(
-        "SELECT  count(fw1.wiki_id) as wam_results_total  FROM `fact_wam_scores` `fw1` left join `fact_wam_scores` `fw2` ON ((fw1.wiki_id = fw2.wiki_id) AND (fw2.time_id = FROM_UNIXTIME(1466380800))) left join `dimension_wikis` `dw` ON ((fw1.wiki_id = dw.wiki_id))  WHERE (fw1.time_id = FROM_UNIXTIME(1466467200)) AND (dw.url like '%%' OR dw.title like '%%') AND fw1.vertical_id IN ('0','1','2','3','4','5','6','7')  AND (fw1.wiki_id NOT IN ('23312','70256','168929','463633','381622','524772','476782','9764','214934','170145','529622','52149','96420','390','468156','690804','197434','29197','88043','37317','466775','402313','169142','746246','119847','57268','1089624')) AND ((dw.url IS NOT NULL AND dw.title IS NOT NULL))"
+        "SELECT  count(fw1.wiki_id) as wam_results_total  "
+        "FROM `fact_wam_scores` `fw1` left join `fact_wam_scores` `fw2` "
+        "ON ((fw1.wiki_id = fw2.wiki_id) "
+        "AND (fw2.time_id = FROM_UNIXTIME(1466380800))) "
+        "left join `dimension_wikis` `dw` ON ((fw1.wiki_id = dw.wiki_id))  "
+        "WHERE (fw1.time_id = FROM_UNIXTIME(1466467200)) "
+        "AND (dw.url like '%%' OR dw.title like '%%') "
+        "AND fw1.vertical_id IN ('0','1','2','3','4','5','6','7')  "
+        "AND (fw1.wiki_id NOT IN ('23312','70256','168929','463633','381622','524772',"
+        "'476782','9764','214934','170145','529622','52149','96420','390','468156',"
+        "'690804','197434','29197','88043','37317','466775','402313','169142','746246',"
+        "'119847','57268','1089624')) "
+        "AND ((dw.url IS NOT NULL AND dw.title IS NOT NULL))"
     ).tables
 
     assert ["rollup_wiki_pageviews"] == Parser(
-        "SELECT date_format(time_id,'%Y-%m-%d') AS date, pageviews AS cnt         FROM rollup_wiki_pageviews      WHERE period_id = '2'   AND wiki_id = '1676379'         AND time_id BETWEEN '2018-01-08'        AND '2018-01-01'"
+        "SELECT date_format(time_id,'%Y-%m-%d') AS date, pageviews AS cnt         "
+        "FROM rollup_wiki_pageviews      "
+        "WHERE period_id = '2'   "
+        "AND wiki_id = '1676379'         "
+        "AND time_id BETWEEN '2018-01-08'        "
+        "AND '2018-01-01'"
     ).tables
 
     # JOINs
     assert ["product_a.users", "product_b.users"] == Parser(
-        "SELECT a.* FROM product_a.users AS a JOIN product_b.users AS b ON a.ip_address = b.ip_address"
+        "SELECT a.* FROM product_a.users AS a "
+        "JOIN product_b.users AS b ON a.ip_address = b.ip_address"
     ).tables
 
     assert ["redirect", "page"] == Parser(
@@ -154,7 +204,8 @@ def test_update_and_replace():
 
     # REPLACE queries
     assert ["page_props"] == Parser(
-        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) VALUES ('47','infoboxes','')"
+        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) "
+        "VALUES ('47','infoboxes','')"
     ).tables
 
 
@@ -184,7 +235,8 @@ def test_three_part_qualified_names():
     ).tables
 
     assert ["MYDB1.MYSCHEMA1.MYTABLE1", "MYDB2.MYSCHEMA2.MYTABLE2"] == Parser(
-        "SELECT * FROM MYDB1.MYSCHEMA1.MYTABLE1 A LEFT JOIN MYDB2.MYSCHEMA2.MYTABLE2 B ON A.COL = B.COL"
+        "SELECT * FROM MYDB1.MYSCHEMA1.MYTABLE1 A "
+        "LEFT JOIN MYDB2.MYSCHEMA2.MYTABLE2 B ON A.COL = B.COL"
     ).tables
 
     assert ["MYDB1.MYSCHEMA1.MYTABLE1", "MYDB2.MYSCHEMA2.MYTABLE2"] == Parser(
@@ -205,7 +257,9 @@ def test_insert_queries():
     assert ["foo"] == Parser("INSERT INTO `foo` (id,text) VALUES (X,X)").tables
 
     assert ["page_vote"] == Parser(
-        "INSERT /* VoteHelper::addVote xxx */  INTO `page_vote` (article_id,user_id,time) VALUES ('442001','27574631','20180228130846')"
+        "INSERT /* VoteHelper::addVote xxx */  "
+        "INTO `page_vote` (article_id,user_id,time) "
+        "VALUES ('442001','27574631','20180228130846')"
     ).tables
 
 
@@ -234,9 +288,10 @@ def test_table_name_with_group_by():
     assert (
         Parser(
             """
-                    SELECT s.cust_id,count(s.cust_id) FROM SH.sales s
-                    GROUP BY s.cust_id HAVING s.cust_id != '1660' AND s.cust_id != '2'
-                        """.strip()
+            SELECT s.cust_id,count(s.cust_id) FROM SH.sales s
+            GROUP BY s.cust_id HAVING s.cust_id != '1660'
+            AND s.cust_id != '2'
+            """.strip()
         ).tables
         == expected_tables
     )
@@ -245,15 +300,18 @@ def test_table_name_with_group_by():
 def test_datasets():
     # see https://github.com/macbre/sql-metadata/issues/38
     assert Parser(
-        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY FROM TABLE1 AS A, TABLE2 AS B"
+        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY "
+        "FROM TABLE1 AS A, TABLE2 AS B"
     ).tables == ["TABLE1", "TABLE2"]
 
     assert Parser(
-        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY FROM DATASET1.TABLE1, DATASET2.TABLE2"
+        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY "
+        "FROM DATASET1.TABLE1, DATASET2.TABLE2"
     ).tables == ["DATASET1.TABLE1", "DATASET2.TABLE2"]
 
     assert Parser(
-        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY FROM DATASET1.TABLE1 AS A, DATASET2.TABLE2 AS B"
+        "SELECT A.FIELD1, B.FIELD1, (A.FIELD1 * B.FIELD1) AS QTY "
+        "FROM DATASET1.TABLE1 AS A, DATASET2.TABLE2 AS B"
     ).tables == ["DATASET1.TABLE1", "DATASET2.TABLE2"]
 
 
@@ -309,38 +367,38 @@ WHERE bar = '1') t
 
 def test_db2_query():
     query = """
-    SELECT ca.IDENTIFICATION_CODE identificationCode, 
-eo.KBO_NUMBER kboNumber, 
+    SELECT ca.IDENTIFICATION_CODE identificationCode,
+eo.KBO_NUMBER kboNumber,
 eo.PARTY_NAME,
-ca.total_guaranteed totale_borgtocht, 
-coalesce(sum(ae1.remainder),0) Saldo, 
-coalesce(sum(ae3.remainder),0) uitstel_van_betaling, 
-coalesce(sum(ae4.remainder),0) reservering_aangifte, 
+ca.total_guaranteed totale_borgtocht,
+coalesce(sum(ae1.remainder),0) Saldo,
+coalesce(sum(ae3.remainder),0) uitstel_van_betaling,
+coalesce(sum(ae4.remainder),0) reservering_aangifte,
 coalesce(sum(ae5.remainder),0) reservering_vergunning,
-coalesce(sum(ae6.remainder),0) zekerheid_douanevervoer, 
+coalesce(sum(ae6.remainder),0) zekerheid_douanevervoer,
 coalesce(sum(ae7.remainder),0) zekerheid_accijnsbeweging,
-coalesce(sum(ae8.remainder),0) FRCT 
-from CUSTOMER_ACCOUNT ca 
-inner join economic_operator eo on eo.id = ca.economic_operator_id 
-join contact_details cd on cd.id = ca.contact_details_id 
-left join ( ca1_remainder_total_guaranteed crtg 
+coalesce(sum(ae8.remainder),0) FRCT
+from CUSTOMER_ACCOUNT ca
+inner join economic_operator eo on eo.id = ca.economic_operator_id
+join contact_details cd on cd.id = ca.contact_details_id
+left join ( ca1_remainder_total_guaranteed crtg
 inner join accounting_entity ae1 on ae1.id = crtg.accounting_entity_id)
-on crtg.id = ca.ca1_id 
-left join (ca3_credit_account cca inner join accounting_entity ae3 on ae3.id = 
-cca.accounting_entity_id) on cca.id = ca.ca3_id 
-left join (ca4_reservations_declaration crd inner join accounting_entity ae4 on 
-ae4.id = crd.accounting_entity_id) on crd.id = ca.ca4_id 
-left join (ca5_reservations_permits crp inner join accounting_entity ae5 on ae5.id 
-= crp.accounting_entity_id) on crp.id = ca.ca5_id 
-left join (CA6_GUARANTEE_CUSTOMS_TRANSPORT gct inner join accounting_entity ae6 on 
-ae6.id = gct.accounting_entity_id) on gct.id = ca.ca6_id 
-left join (CA7_GUARANTEE_EXCISE_PRODUCTS gep inner join accounting_entity ae7 on 
-ae7.id = gep.accounting_entity_id) on gep.id = ca.ca7_id 
-left join (ca8_frct cf inner join ca8_frct_per_discharge cfpd on cfpd.CA8_ID = 
-cf.id inner join accounting_entity ae8 on ae8.id = cfpd.accounting_entity_id) on 
-cf.id = ca.ca8_id 
-group by eo.PARTY_NAME,eo.KBO_NUMBER, ca.IDENTIFICATION_CODE, ca.total_guaranteed 
-order by eo.KBO_NUMBER, ca.IDENTIFICATION_CODE 
+on crtg.id = ca.ca1_id
+left join (ca3_credit_account cca inner join accounting_entity ae3 on ae3.id =
+cca.accounting_entity_id) on cca.id = ca.ca3_id
+left join (ca4_reservations_declaration crd inner join accounting_entity ae4 on
+ae4.id = crd.accounting_entity_id) on crd.id = ca.ca4_id
+left join (ca5_reservations_permits crp inner join accounting_entity ae5 on ae5.id
+= crp.accounting_entity_id) on crp.id = ca.ca5_id
+left join (CA6_GUARANTEE_CUSTOMS_TRANSPORT gct inner join accounting_entity ae6 on
+ae6.id = gct.accounting_entity_id) on gct.id = ca.ca6_id
+left join (CA7_GUARANTEE_EXCISE_PRODUCTS gep inner join accounting_entity ae7 on
+ae7.id = gep.accounting_entity_id) on gep.id = ca.ca7_id
+left join (ca8_frct cf inner join ca8_frct_per_discharge cfpd on cfpd.CA8_ID =
+cf.id inner join accounting_entity ae8 on ae8.id = cfpd.accounting_entity_id) on
+cf.id = ca.ca8_id
+group by eo.PARTY_NAME,eo.KBO_NUMBER, ca.IDENTIFICATION_CODE, ca.total_guaranteed
+order by eo.KBO_NUMBER, ca.IDENTIFICATION_CODE
 with ur
     """
     parser = Parser(query)
@@ -423,23 +481,28 @@ with ur
 def test_get_tables_with_leading_digits():
     # see #139
 
-    # Identifiers may begin with a digit but unless quoted may not consist solely of digits.
+    # Identifiers may begin with a digit
+    # but unless quoted may not consist solely of digits.
     assert ["0020"] == Parser("SELECT * FROM `0020`").tables
 
     assert ["0020_big_table"] == Parser(
-        "SELECT t.val as value, count(*) FROM `0020_big_table` as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
+        "SELECT t.val as value, count(*) "
+        "FROM `0020_big_table` as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
     ).tables
     assert ["0020_big_table"] == Parser(
         "SELECT t.val as value, count(*) FROM `0020_big_table`"
     ).tables
     assert ["0020_big_table"] == Parser(
-        'SELECT t.val as value, count(*) FROM "0020_big_table" as t WHERE id BETWEEN 10 AND 20 GROUP BY val'
+        "SELECT t.val as value, count(*) "
+        'FROM "0020_big_table" as t WHERE id BETWEEN 10 AND 20 GROUP BY val'
     ).tables
     assert ["0020_big_table"] == Parser(
-        "SELECT t.val as value, count(*) FROM 0020_big_table as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
+        "SELECT t.val as value, count(*) "
+        "FROM 0020_big_table as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
     ).tables
     assert ["0020_big_table"] == Parser(
-        "SELECT t.val as value, count(*) FROM `0020_big_table` as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
+        "SELECT t.val as value, count(*) "
+        "FROM `0020_big_table` as t WHERE id BETWEEN 10 AND 20 GROUP BY val"
     ).tables
     assert ["0020_big_table"] == Parser(
         "SELECT t.val as value, count(*) FROM 0020_big_table"
@@ -456,3 +519,32 @@ def test_insert_ignore_with_comments():
 
     for query in queries:
         assert ["bar"] == Parser(query).tables
+
+
+def test_mutli_from_aliases_without_as():
+    query = """
+    select distinct e1.eid as eid from uw_emp "e1", uw_emp "e2", uw_payroll p
+    where e1.eid = e2.eid and e1.eid = p.eid
+    """
+    parser = Parser(query)
+    assert parser.tables == ["uw_emp", "uw_payroll"]
+    assert parser.tables_aliases == {"p": "uw_payroll", "e1": "uw_emp", "e2": "uw_emp"}
+
+
+def test_tables_with_aggregation():
+    query = """
+    SELECT
+    tc.col2
+    , max(tc.col3) col3_mx
+    , trunc(max(tc.col4)) col4_mx
+    , extract (week from (max(tc.col5))) col5_week
+    , sum(NVL(tc.amt,0)) tot_amt
+    FROM
+    my_sc.tab1 tc
+    WHERE
+    tc.col1 = 'AAA'
+    group by
+    tc.col2
+    """
+    parser = Parser(query)
+    assert parser.tables == ["my_sc.tab1"]
diff --git a/test/test_hive.py b/test/test_hive.py
index 94a0c8c..7dd00b4 100644
--- a/test/test_hive.py
+++ b/test/test_hive.py
@@ -29,11 +29,13 @@ FROM
      (
        year > '{{ beginYear28 }}' OR
        (year = '{{ beginYear28 }}' AND month > '{{ beginMonth28 }}') OR
-       (year = '{{ beginYear28 }}' AND month = '{{ beginMonth28 }}' AND day > '{{ beginDay28 }}')
+       (year = '{{ beginYear28 }}' AND month = '{{ beginMonth28 }}'
+       AND day > '{{ beginDay28 }}')
      ) AND (
        year < '{{ beginYear }}' OR
        (year = '{{ beginYear }}' AND month < '{{ beginMonth }}') OR
-       (year = '{{ beginYear }}' AND month = '{{ beginMonth }}' AND day <= '{{ beginDay }}')
+       (year = '{{ beginYear }}' AND month = '{{ beginMonth }}'
+       AND day <= '{{ beginDay }}')
      )
    GROUP BY wiki_id, beacon) r
 JOIN statsdb.dimension_wikis d ON r.wiki_id = d.wiki_id;
diff --git a/test/test_limit_and_offset.py b/test/test_limit_and_offset.py
index 218218c..024e935 100644
--- a/test/test_limit_and_offset.py
+++ b/test/test_limit_and_offset.py
@@ -39,7 +39,8 @@ def test_comma_separated():
 
     assert Parser(
         "SELECT /* CategoryPaginationViewer::processSection */  "
-        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  FROM `page` "
+        "page_namespace,page_title,page_len,page_is_redirect,cl_sortkey_prefix  "
+        "FROM `page` "
         "INNER JOIN `categorylinks` FORCE INDEX (cl_sortkey) ON ((cl_from = page_id))  "
         "WHERE cl_type = 'page' AND cl_to = 'Spotify/Song'  "
         "ORDER BY cl_sortkey LIMIT 927600,200"
diff --git a/test/test_mssql_server.py b/test/test_mssql_server.py
index c4c3054..a565ab1 100644
--- a/test/test_mssql_server.py
+++ b/test/test_mssql_server.py
@@ -45,7 +45,7 @@ def test_sql_server_cte():
                 WITH foo AS (
                     SELECT * FROM n
                 )
-                UPDATE z from foo set z.q = foo.y 
+                UPDATE z from foo set z.q = foo.y
                     """
         ).tables
         == ["n", "z"]
@@ -54,10 +54,10 @@ def test_sql_server_cte():
     assert (
         Parser(
             """
-                WITH foo AS ( 
+                WITH foo AS (
                      SELECT * FROM tab
-                ) 
-                DELETE FROM z JOIN foo ON z.a = foo.a  
+                )
+                DELETE FROM z JOIN foo ON z.a = foo.a
                     """.strip()
         ).tables
         == ["tab", "z"]
@@ -67,20 +67,20 @@ def test_sql_server_cte():
 def test_sql_server_cte_sales_by_year():
     sales_query = """
 WITH cte_sales AS (
-    SELECT 
-        staff_id, 
-        COUNT(*) order_count  
+    SELECT
+        staff_id,
+        COUNT(*) order_count
     FROM
         sales.orders
-    WHERE 
+    WHERE
         YEAR(order_date) = 2018
     GROUP BY
         staff_id
 )
 SELECT
     AVG(order_count) average_orders_by_staff
-FROM 
-    cte_sales;  
+FROM
+    cte_sales;
     """.strip()
 
     parser = Parser(sales_query)
diff --git a/test/test_multiple_subqueries.py b/test/test_multiple_subqueries.py
index cacaa86..dbc38ba 100644
--- a/test/test_multiple_subqueries.py
+++ b/test/test_multiple_subqueries.py
@@ -8,28 +8,36 @@ SELECT main_qry.*,
        subdays.DAYS_OFFER2,
        subdays.DAYS_OFFER3
 from (
-         SELECT jr.id                                                                                   as PROJECT_ID,
+         SELECT jr.id  as PROJECT_ID,
                 5 * (DATEDIFF(ifnull(lc.creation_date, now()), jr.creation_date) DIV 7)
                     + MID('0123444401233334012222340111123400001234000123440',
-                          7 * WEEKDAY(jr.creation_date) + WEEKDAY(ifnull(lc.creation_date, now())) + 1, 1) as LIFETIME,
+                          7 * WEEKDAY(jr.creation_date)
+                          + WEEKDAY(ifnull(lc.creation_date, now())) + 1, 1)
+                          as LIFETIME,
                 count(distinct
-                      case when jra.application_source = 'VERAMA' then jra.id else null end)                 NUM_APPLICATIONS,
-                count(distinct jra.id)                                                                   NUM_CANDIDATES,
-                sum(case when jro.stage = 'DEAL' then 1 else 0 end)                                 as NUM_CONTRACTED,
-                sum(ifnull(IS_INTERVIEW, 0))                                                            as NUM_INTERVIEWED,
-                sum(ifnull(IS_PRESENTATION, 0))                                                         as NUM_OFFERED
+                      case when jra.application_source = 'VERAMA'
+                        then jra.id else null end)        NUM_APPLICATIONS,
+                count(distinct jra.id) NUM_CANDIDATES,
+                sum(case when jro.stage = 'DEAL' then 1 else 0 end) as NUM_CONTRACTED,
+                sum(ifnull(IS_INTERVIEW, 0)) as NUM_INTERVIEWED,
+                sum(ifnull(IS_PRESENTATION, 0)) as NUM_OFFERED
          from job_request jr
                   left join job_request_application jra on jr.id = jra.job_request_id
-                  left join job_request_offer jro on jro.job_request_application_id = jra.id
-                  left join lifecycle lc on lc.object_id=jr.id and lc.lifecycle_object_type='JOB_REQUEST' 
+                  left join job_request_offer jro
+                  on jro.job_request_application_id = jra.id
+                  left join lifecycle lc on lc.object_id=jr.id
+                  and lc.lifecycle_object_type='JOB_REQUEST'
                   and lc.event = 'JOB_REQUEST_CLOSED'
                   left join (SELECT jro2.job_request_application_id,
                                     max(case
-                                            when jro2.first_interview_scheduled_date is not null then 1
-                                            else 0 end)                                                    as IS_INTERVIEW,
-                                    max(case when jro2.first_presented_date is not null then 1 else 0 end) as IS_PRESENTATION
+                                            when jro2.first_interview_scheduled_date
+                                            is not null then 1
+                                            else 0 end) as IS_INTERVIEW,
+                                    max(case when jro2.first_presented_date is not null
+                                    then 1 else 0 end) as IS_PRESENTATION
                              from job_request_offer jro2
-                             group by 1) jrah2 on jra.id = jrah2.job_request_application_id
+                             group by 1) jrah2
+                             on jra.id = jrah2.job_request_application_id
                   left join client u on jr.client_id = u.id
          where jr.from_point_break = 0
            and u.name not in ('Test', 'Demo Client')
@@ -43,22 +51,27 @@ from (
                  days_to_offer,
                  (SELECT count(distinct jro.job_request_application_id)
                   from job_request_offer jro
-                           left join job_request_application jra2 on jro.job_request_application_id = jra2.id
+                           left join job_request_application jra2
+                           on jro.job_request_application_id = jra2.id
                   where jra2.job_request_id = PROJECT_ID
                     and jro.first_presented_date is not null
                     and jro.first_presented_date <= InitialChangeDate
                  ) as RowNo
           from (
                    SELECT jr.id                    as PROJECT_ID,
-                          5 * (DATEDIFF(jro.first_presented_date, jr.creation_date) DIV 7) +
+                          5 * (
+                          DATEDIFF(jro.first_presented_date, jr.creation_date) DIV 7) +
                           MID('0123444401233334012222340111123400001234000123440',
-                              7 * WEEKDAY(jr.creation_date) + WEEKDAY(jro.first_presented_date) + 1,
+                              7 * WEEKDAY(jr.creation_date)
+                              + WEEKDAY(jro.first_presented_date) + 1,
                               1)                   as days_to_offer,
                           jro.job_request_application_id,
                           jro.first_presented_date as InitialChangeDate
                    from presentation pr
-                            left join presentation_job_request_offer pjro on pr.id = pjro.presentation_id
-                            left join job_request_offer jro on pjro.job_request_offer_id = jro.id
+                            left join presentation_job_request_offer pjro
+                            on pr.id = pjro.presentation_id
+                            left join job_request_offer jro
+                            on pjro.job_request_offer_id = jro.id
                             left join job_request jr on pr.job_request_id = jr.id
                    where jro.first_presented_date is not null) days_sqry) days_final_qry
     group by PROJECT_ID) subdays
@@ -246,7 +259,8 @@ task_type_id = 80
     }
 
     assert parser.subqueries == {
-        "a": "SELECT std.task_id as new_task_id FROM some_task_detail std WHERE std.STATUS = 1",
+        "a": "SELECT std.task_id as new_task_id "
+        "FROM some_task_detail std WHERE std.STATUS = 1",
         "b": "SELECT st.task_id FROM some_task st WHERE task_type_id = 80",
     }
 
@@ -308,10 +322,10 @@ def test_resolving_columns_in_sub_queries_with_join_between_sub_queries():
     Select sq.sub_alias, sq.other_name from (
         select tab1.aa sub_alias, tab2.us as other_name from tab1
         left join tab2 on tab1.id = tab2.other_id
-    ) sq 
+    ) sq
     left join (
         select intern1 as col1, secret col2 from aa
-    ) sq3 on sq.sub_alias = sq3.col1 
+    ) sq3 on sq.sub_alias = sq3.col1
     order by sq.other_name, sq3.col2
     """
 
@@ -343,10 +357,10 @@ def test_resolving_columns_in_sub_queries_union():
     Select sq.sub_alias, sq.other_name from (
         select tab1.aa sub_alias, tab2.us as other_name from tab1
         left join tab2 on tab1.id = tab2.other_id
-    ) sq 
-    union all 
-    select sq3.col1, sq3.col2 from 
-    (select tab12.col1, concat(tab23.ab, ' ', tab23.bc) as col2 
+    ) sq
+    union all
+    select sq3.col1, sq3.col2 from
+    (select tab12.col1, concat(tab23.ab, ' ', tab23.bc) as col2
     from tab12 left join tab23 on tab12.id = tab23.zorro) sq3
     """
 
diff --git a/test/test_normalization.py b/test/test_normalization.py
index 7cefdde..5aced76 100644
--- a/test/test_normalization.py
+++ b/test/test_normalization.py
@@ -14,67 +14,143 @@ def test_generalization_of_sql():
 
     assert (
         Parser(
-            "UPDATE  `category` SET cat_pages = cat_pages + 1,cat_files = cat_files + 1 WHERE cat_title = 'foo'"
+            "UPDATE  `category` SET cat_pages = cat_pages + 1,cat_files = cat_files + 1"
+            " WHERE cat_title = 'foo'"
         ).generalize
-        == "UPDATE `category` SET cat_pages = cat_pages + N,cat_files = cat_files + N WHERE cat_title = X"
+        == "UPDATE `category` SET cat_pages = cat_pages + N,cat_files = cat_files + N"
+        " WHERE cat_title = X"
     )
 
     assert (
         Parser(
-            "SELECT  entity_key  FROM `wall_notification_queue`  WHERE (wiki_id = ) AND (event_date > '20150105141012')"
+            "SELECT  entity_key  FROM `wall_notification_queue`  WHERE (wiki_id = ) "
+            "AND (event_date > '20150105141012')"
         ).generalize
-        == "SELECT entity_key FROM `wall_notification_queue` WHERE (wiki_id = ) AND (event_date > X)"
+        == "SELECT entity_key FROM `wall_notification_queue` WHERE (wiki_id = ) "
+        "AND (event_date > X)"
     )
 
     assert (
         Parser(
-            "UPDATE  `user` SET user_touched = '20150112143631' WHERE user_id = '25239755'"
+            "UPDATE  `user` SET user_touched = '20150112143631' "
+            "WHERE user_id = '25239755'"
         ).generalize
         == "UPDATE `user` SET user_touched = X WHERE user_id = X"
     )
 
     assert (
         Parser(
-            "SELECT /* CategoryDataService::getMostVisited 207.46.13.56 */  page_id,cl_to  FROM `page` INNER JOIN `categorylinks` ON ((cl_from = page_id))  WHERE cl_to = 'Characters' AND (page_namespace NOT IN(500,6,14))  ORDER BY page_title"
+            "SELECT /* CategoryDataService::getMostVisited 207.46.13.56 */  "
+            "page_id,cl_to  FROM `page` "
+            "INNER JOIN `categorylinks` ON ((cl_from = page_id))  "
+            "WHERE cl_to = 'Characters' "
+            "AND (page_namespace NOT IN(500,6,14))  ORDER BY page_title"
         ).generalize
-        == "SELECT page_id,cl_to FROM `page` INNER JOIN `categorylinks` ON ((cl_from = page_id)) WHERE cl_to = X AND (page_namespace NOT IN (XYZ)) ORDER BY page_title"
+        == "SELECT page_id,cl_to FROM `page` "
+        "INNER JOIN `categorylinks` ON ((cl_from = page_id)) "
+        "WHERE cl_to = X AND (page_namespace NOT IN (XYZ)) ORDER BY page_title"
     )
 
     assert (
         Parser(
-            "SELECT /* ArticleCommentList::getCommentList Dancin'NoViolen... */  page_id,page_title  FROM `page`  WHERE (page_title LIKE 'Dreams\\_Come\\_True/@comment-%' ) AND page_namespace = '1'  ORDER BY page_id DESC"
+            "SELECT /* ArticleCommentList::getCommentList Dancin'NoViolen... */  "
+            "page_id,page_title  FROM `page`  "
+            "WHERE (page_title LIKE 'Dreams\\_Come\\_True/@comment-%' ) "
+            "AND page_namespace = '1'  ORDER BY page_id DESC"
         ).generalize
-        == "SELECT page_id,page_title FROM `page` WHERE (page_title LIKE X ) AND page_namespace = X ORDER BY page_id DESC"
+        == "SELECT page_id,page_title FROM `page` "
+        "WHERE (page_title LIKE X ) AND page_namespace = X ORDER BY page_id DESC"
     )
 
     assert (
         Parser(
-            "delete /* DatabaseBase::sourceFile( /usr/wikia/slot1/3690/src/maintenance/cleanupStarter.sql ) CreateWiki scri... */ from text where old_id not in (select rev_text_id from revision)"
+            "delete "
+            "/* "
+            "DatabaseBase::sourceFile(/usr/wikia/src/maintenance/cleanupStarter.sql ) "
+            "CreateWiki scri... */ "
+            "from text where old_id not in (select rev_text_id from revision)"
         ).generalize
         == "delete from text where old_id not in (select rev_text_id from revision)"
     )
 
     assert (
         Parser(
-            "SELECT /* WallNotifications::getBackupData Craftindiedo */  id,is_read,is_reply,unique_id,entity_key,author_id,notifyeveryone  FROM `wall_notification`  WHERE user_id = '24944488' AND wiki_id = '1030786' AND unique_id IN ('880987','882618','708228','522330','662055','837815','792393','341504','600103','612640','667267','482428','600389','213400','620177','164442','659210','621286','609757','575865','567668','398132','549770','495396','344814','421448','400650','411028','341771','379461','332587','314176','284499','250207','231714')  AND is_hidden = '0'  ORDER BY id"
+            "SELECT /* WallNotifications::getBackupData Craftindiedo */  "
+            "id,is_read,is_reply,unique_id,entity_key,author_id,notifyeveryone  "
+            "FROM `wall_notification`  WHERE user_id = '24944488' "
+            "AND wiki_id = '1030786' AND unique_id "
+            "IN ('880987','882618','708228','522330','662055','837815','792393')  "
+            "AND is_hidden = '0'  ORDER BY id"
         ).generalize
-        == "SELECT id,is_read,is_reply,unique_id,entity_key,author_id,notifyeveryone FROM `wall_notification` WHERE user_id = X AND wiki_id = X AND unique_id IN (XYZ) AND is_hidden = X ORDER BY id"
+        == "SELECT id,is_read,is_reply,unique_id,entity_key,author_id,notifyeveryone "
+        "FROM `wall_notification` WHERE user_id = X AND wiki_id = X "
+        "AND unique_id IN (XYZ) AND is_hidden = X ORDER BY id"
     )
 
     # comments with * inside
     assert (
         Parser(
-            "SELECT /* ArticleCommentList::getCommentList *Crashie* */  page_id,page_title  FROM `page`  WHERE (page_title LIKE 'Dainava/@comment-%' ) AND page_namespace = '1201'  ORDER BY page_id DESC"
+            "SELECT /* ArticleCommentList::getCommentList *Crashie* */  "
+            "page_id,page_title  FROM `page`  "
+            "WHERE (page_title LIKE 'Dainava/@comment-%' ) "
+            "AND page_namespace = '1201'  ORDER BY page_id DESC"
         ).generalize
-        == "SELECT page_id,page_title FROM `page` WHERE (page_title LIKE X ) AND page_namespace = X ORDER BY page_id DESC"
+        == "SELECT page_id,page_title FROM `page` "
+        "WHERE (page_title LIKE X ) "
+        "AND page_namespace = X ORDER BY page_id DESC"
     )
 
     # comments with * inside
     assert (
         Parser(
-            "SELECT /* ListusersData::loadData Lart96 - 413bc6e5-b151-44fd-80bd-3baff733fb91 */  count(0) as cnt  FROM `events_local_users`  WHERE wiki_id = '7467' AND (user_name != '') AND user_is_closed = '0' AND ( single_group = 'poweruser' or  all_groups = ''  or  all_groups  LIKE '%bot'  or  all_groups  LIKE '%bot;%'  or  all_groups  LIKE '%bureaucrat'  or  all_groups  LIKE '%bureaucrat;%'  or  all_groups  LIKE '%sysop'  or  all_groups  LIKE '%sysop;%'  or  all_groups  LIKE '%authenticated'  or  all_groups  LIKE '%authenticated;%'  or  all_groups  LIKE '%bot-global'  or  all_groups  LIKE '%bot-global;%'  or  all_groups  LIKE '%content-reviewer'  or  all_groups  LIKE '%content-reviewer;%'  or  all_groups  LIKE '%council'  or  all_groups  LIKE '%council;%'  or  all_groups  LIKE '%fandom-editor'  or  all_groups  LIKE '%fandom-editor;%'  or  all_groups  LIKE '%helper'  or  all_groups  LIKE '%helper;%'  or  all_groups  LIKE '%restricted-login'  or  all_groups  LIKE '%restricted-login;%'  or  all_groups  LIKE '%restricted-login-exempt'  or  all_groups  LIKE '%restricted-login-exempt;%'  or  all_groups  LIKE '%reviewer'  or  all_groups  LIKE '%reviewer;%'  or  all_groups  LIKE '%staff'  or  all_groups  LIKE '%staff;%'  or  all_groups  LIKE '%translator'  or  all_groups  LIKE '%translator;%'  or  all_groups  LIKE '%util'  or  all_groups  LIKE '%util;%'  or  all_groups  LIKE '%vanguard'  or  all_groups  LIKE '%vanguard;%'  or  all_groups  LIKE '%voldev'  or  all_groups  LIKE '%voldev;%'  or  all_groups  LIKE '%vstf'  or  all_groups  LIKE '%vstf;%' ) AND ( edits >= 5)  LIMIT 1  "
+            "SELECT "
+            "/* "
+            "ListusersData::loadData Lart96 - 413bc6e5-b151-44fd-80bd-3baff733fb91 "
+            "*/"
+            " count(0) as cnt  "
+            "FROM `events_local_users`  "
+            "WHERE wiki_id = '7467' "
+            "AND (user_name != '') AND user_is_closed = '0' "
+            "AND ( single_group = 'poweruser' or  all_groups = ''  "
+            "or  all_groups  LIKE '%bot'  or  all_groups  LIKE '%bot;%'  "
+            "or  all_groups  LIKE '%bureaucrat'  or  all_groups  LIKE '%bureaucrat;%'  "
+            "or  all_groups  LIKE '%sysop'  or  all_groups  LIKE '%sysop;%'  "
+            "or  all_groups  LIKE '%authenticated'  "
+            "or  all_groups  LIKE '%authenticated;%'  "
+            "or  all_groups  LIKE '%bot-global'  "
+            "or  all_groups  LIKE '%bot-global;%'  "
+            "or  all_groups  LIKE '%content-reviewer'  "
+            "or  all_groups  LIKE '%content-reviewer;%'  "
+            "or  all_groups  LIKE '%council'  "
+            "or  all_groups  LIKE '%council;%'  "
+            "or  all_groups  LIKE '%fandom-editor'  "
+            "or  all_groups  LIKE '%fandom-editor;%'  "
+            "or  all_groups  LIKE '%helper'  "
+            "or  all_groups  LIKE '%helper;%'  "
+            "or  all_groups  LIKE '%restricted-login'  "
+            "or  all_groups  LIKE '%restricted-login;%'  "
+            "or  all_groups  LIKE '%restricted-login-exempt'  "
+            "or  all_groups  LIKE '%restricted-login-exempt;%'  "
+            "or  all_groups  LIKE '%reviewer'  "
+            "or  all_groups  LIKE '%reviewer;%'  "
+            "or  all_groups  LIKE '%staff'  "
+            "or  all_groups  LIKE '%staff;%'  "
+            "or  all_groups  LIKE '%translator'  "
+            "or  all_groups  LIKE '%translator;%'  "
+            "or  all_groups  LIKE '%util'  "
+            "or  all_groups  LIKE '%util;%'  "
+            "or  all_groups  LIKE '%vanguard'  "
+            "or  all_groups  LIKE '%vanguard;%'  "
+            "or  all_groups  LIKE '%voldev'  "
+            "or  all_groups  LIKE '%voldev;%'  "
+            "or  all_groups  LIKE '%vstf'  "
+            "or  all_groups  LIKE '%vstf;%' ) AND ( edits >= 5)  LIMIT 1  "
         ).generalize
-        == "SELECT count(N) as cnt FROM `events_local_users` WHERE wiki_id = X AND (user_name != X) AND user_is_closed = X AND ( single_group = X or all_groups = X or all_groups LIKE X ... ) AND ( edits >= N) LIMIT N"
+        == "SELECT count(N) as cnt FROM `events_local_users` "
+        "WHERE wiki_id = X AND (user_name != X) "
+        "AND user_is_closed = X "
+        "AND ( single_group = X or all_groups = X or all_groups LIKE X ... ) "
+        "AND ( edits >= N) LIMIT N"
     )
 
     # multiline query
@@ -87,7 +163,8 @@ def test_generalization_of_sql():
 
     assert (
         Parser(sql).generalize
-        == "SELECT page_title FROM page WHERE page_namespace = X AND page_title COLLATE LATINN_GENERAL_CI LIKE X"
+        == "SELECT page_title FROM page WHERE page_namespace = X "
+        "AND page_title COLLATE LATINN_GENERAL_CI LIKE X"
     )
 
     # queries with IN + brackets (#21)
@@ -103,23 +180,32 @@ def test_generalization_of_sql():
 
     assert (
         Parser(
-            "SELECT foo FROM bar WHERE slug in (         'american-horror-story', 'animated-series', 'batman', 'comics', 'dc', 'fallout',          'game-of-thrones', 'hbo', 'horror', 'marvel', 'mcu', 'movie-reviews', 'movie-trailers',          'movies', 'netflix', 'playstation', 'star-wars', 'stranger-things', 'streaming',          'the-simpsons', 'zelda'       )"
+            "SELECT foo FROM bar WHERE slug in ('american-horror-story', "
+            "'animated-series', 'batman', 'comics', 'dc', 'fallout',"
+            "'game-of-thrones', 'hbo', 'horror', 'marvel', 'mcu', "
+            "'movie-reviews', 'movie-trailers', 'movies', 'netflix', "
+            "'playstation', 'star-wars', 'stranger-things', 'streaming',"
+            "'the-simpsons', 'zelda')"
         ).generalize
         == "SELECT foo FROM bar WHERE slug in (XYZ)"
     )
 
     assert (
         Parser(
-            "SELECT curation_cms.topics.slug from curation_cms.topics where curation_cms.topics.id in (   87, 86, 79, 77, 76, 73, 72, 70, 71, 69, 68, 66, 65, 64, 62, 63, 2, 57, 17, 1,    22, 49, 30, 55, 15, 3, 48, 43, 24, 47, 45, 10, 50, 39, 36, 8, 34, 25, 13, 6, 4 )"
+            "SELECT curation_cms.topics.slug "
+            "from curation_cms.topics where curation_cms.topics.id "
+            "in ( 55, 15, 3, 48, 43, 24, 47, 45, 10, 50, 39, 36, 8, 34, 25, 13, 6, 4 )"
         ).generalize
-        == "SELECT curation_cms.topics.slug from curation_cms.topics where curation_cms.topics.id in (XYZ)"
+        == "SELECT curation_cms.topics.slug "
+        "from curation_cms.topics where curation_cms.topics.id in (XYZ)"
     )
 
 
 def test_generalize_timestamp():
     assert (
         Parser(
-            # ODBC syntax - https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html
+            # ODBC syntax
+            # https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html
             "SELECT foo FROM bar WHERE publish_date < {ts '2018-04-05 10:14:33.824'}"
         ).generalize
         == "SELECT foo FROM bar WHERE publish_date < {ts X}"
@@ -134,7 +220,14 @@ def test_generalize_insert():
 
     assert (
         Parser(
-            "/* 7e6384e5 */ INSERT into notification_stats.request_info (   type,    request_id,    title,    message,    details ) values (   'action-notification',    '51f8a962-bae0-4d25-9341-130658161541',    'RickSanchez15 replied to What''s your overall favourite Season of South Park?.',    'Cool',    'null' )"
+            "/* 7e6384e5 */ INSERT into notification_stats.request_info "
+            "(   type,    request_id,    title,    message,    details ) "
+            "values ('action-notification', "
+            "'51f8a962-bae0-4d25-9341-130658161541',"
+            "'RickSanchez15 replied to What''s your overall "
+            "favourite Season of South Park?.', "
+            "'Cool','null' )"
         ).generalize
-        == "INSERT into notification_stats.request_info ( type, request_id, title, message, details ) values (XYZ)"
+        == "INSERT into notification_stats.request_info "
+        "( type, request_id, title, message, details ) values (XYZ)"
     )
diff --git a/test/test_postgress.py b/test/test_postgress.py
index 5cb7d1e..d2c8ebb 100644
--- a/test/test_postgress.py
+++ b/test/test_postgress.py
@@ -13,7 +13,8 @@ def test_postgress_quoted_names():
     assert parser.values == ["foo"]
 
     parser = Parser(
-        'SELECT "test"."id", "test"."name" FROM "test" WHERE "test"."name" = \'foo\' LIMIT 21 FOR UPDATE'
+        'SELECT "test"."id", "test"."name" FROM "test" '
+        'WHERE "test"."name" = \'foo\' LIMIT 21 FOR UPDATE'
     )
     assert ["test"] == parser.tables
     assert ["test.id", "test.name"] == parser.columns
diff --git a/test/test_query.py b/test/test_query.py
index 4890348..5a22966 100644
--- a/test/test_query.py
+++ b/test/test_query.py
@@ -20,9 +20,11 @@ def test_preprocessing():
 
     assert (
         Parser(
-            "SELECT r1.wiki_id AS id FROM report_wiki_recent_pageviews AS r1 INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id"
+            "SELECT r1.wiki_id AS id FROM report_wiki_recent_pageviews AS r1 "
+            "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id"
         ).query
-        == "SELECT r1.wiki_id AS id FROM report_wiki_recent_pageviews AS r1 INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id"
+        == "SELECT r1.wiki_id AS id FROM report_wiki_recent_pageviews AS r1 "
+        "INNER JOIN dimension_wikis AS d ON r.wiki_id = d.wiki_id"
     )
 
     # comments are kept
@@ -46,9 +48,11 @@ def test_preprocessing():
     )
     assert (
         Parser(
-            "SELECT * from aa where name = 'test name with \"aa\" in string' and aa =' as \"aa.oo\" '"
+            "SELECT * from aa where name = 'test name with \"aa\" in string' "
+            "and aa =' as \"aa.oo\" '"
         ).query
-        == "SELECT * from aa where name = 'test name with \"aa\" in string' and aa =' as \"aa.oo\" '"
+        == "SELECT * from aa where name = 'test name with \"aa\" in string' "
+        "and aa =' as \"aa.oo\" '"
     )
 
 
diff --git a/test/test_values.py b/test/test_values.py
index 5def787..58b62c9 100644
--- a/test/test_values.py
+++ b/test/test_values.py
@@ -3,7 +3,9 @@ from sql_metadata import Parser
 
 def test_getting_values():
     parser = Parser(
-        "INSERT /* VoteHelper::addVote xxx */  INTO `page_vote` (article_id,user_id,`time`) VALUES ('442001','27574631','20180228130846')"
+        "INSERT /* VoteHelper::addVote xxx */  "
+        "INTO `page_vote` (article_id,user_id,`time`) "
+        "VALUES ('442001','27574631','20180228130846')"
     )
     assert parser.values == ["442001", "27574631", "20180228130846"]
     assert parser.values_dict == {
@@ -14,7 +16,8 @@ def test_getting_values():
 
     # REPLACE queries
     parser = Parser(
-        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) VALUES ('47','infoboxes','')"
+        "REPLACE INTO `page_props` (pp_page,pp_propname,pp_value) "
+        "VALUES ('47','infoboxes','')"
     )
     assert parser.values == ["47", "infoboxes", ""]
     assert parser.values_dict == {
@@ -24,7 +27,8 @@ def test_getting_values():
     }
 
     parser = Parser(
-        "/* method */ INSERT IGNORE INTO `0070_insert_ignore_table` VALUES (9, 2.15, '123', '2017-01-01');"
+        "/* method */ INSERT IGNORE INTO `0070_insert_ignore_table` "
+        "VALUES (9, 2.15, '123', '2017-01-01');"
     )
     assert parser.query_type == "INSERT"
     assert parser.values == [9, 2.15, "123", "2017-01-01"]
@@ -40,7 +44,15 @@ def test_getting_values():
     assert Parser("SELECT * from foo;").values_dict is None
 
     parser = Parser(
-        "INSERT INTO `wp_comments` (`comment_post_ID`, `comment_author`, `comment_author_email`, `comment_author_url`, `comment_author_IP`, `comment_date`, `comment_date_gmt`, `comment_content`, `comment_karma`, `comment_approved`, `comment_agent`, `comment_type`, `comment_parent`, `user_id`) VALUES (1, 'test user', '', '', '127.0.0.1', '2021-02-27 03:21:52', '2021-02-27 03:21:52', 'test comment', 0, '0', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) Gecko/20100101 Firefox/78.0', 'comment', 0, 0)',"
+        "INSERT INTO `wp_comments` (`comment_post_ID`, `comment_author`, "
+        "`comment_author_email`, `comment_author_url`, `comment_author_IP`, "
+        "`comment_date`, `comment_date_gmt`, `comment_content`, `comment_karma`, "
+        "`comment_approved`, `comment_agent`, `comment_type`, `comment_parent`, "
+        "`user_id`) VALUES (1, 'test user', '', '', '127.0.0.1', '2021-02-27 03:21:52',"
+        " '2021-02-27 03:21:52', 'test comment', 0, '0', "
+        "'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) "
+        "Gecko/20100101 Firefox/78.0', "
+        "'comment', 0, 0)',"
     )
     assert parser.values == [
         1,
@@ -53,7 +65,10 @@ def test_getting_values():
         "test comment",
         0,
         "0",
-        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) Gecko/20100101 Firefox/78.0",
+        (
+            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) "
+            "Gecko/20100101 Firefox/78.0"
+        ),
         "comment",
         0,
         0,
@@ -70,7 +85,10 @@ def test_getting_values():
         "comment_content": "test comment",
         "comment_karma": 0,
         "comment_approved": "0",
-        "comment_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) Gecko/20100101 Firefox/78.0",
+        "comment_agent": (
+            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv: 78.0) "
+            "Gecko/20100101 Firefox/78.0"
+        ),
         "comment_type": "comment",
         "comment_parent": 0,
         "user_id": 0,
diff --git a/test/test_with_statements.py b/test/test_with_statements.py
index 28c65b8..c891d9a 100644
--- a/test/test_with_statements.py
+++ b/test/test_with_statements.py
@@ -6,7 +6,7 @@ def test_with_statements():
     parser = Parser(
         """
 WITH
-database1.tableFromWith AS (SELECT aa.* FROM table3 as aa 
+database1.tableFromWith AS (SELECT aa.* FROM table3 as aa
                             left join table4 on aa.col1=table4.col2),
 test as (SELECT * from table3)
 SELECT
@@ -94,9 +94,9 @@ def test_multiple_with_statements_with_with_columns():
     # fix for setting columns in with
     # https://github.com/macbre/sql-metadata/issues/128
     query = """
-    WITH 
+    WITH
     t1 (c1, c2) AS (SELECT * FROM t2),
-    t3 (c3, c4) AS (SELECT c5, c6 FROM t4) 
+    t3 (c3, c4) AS (SELECT c5, c6 FROM t4)
     SELECT * FROM t1, t3;
     """
     parser = Parser(query)
@@ -175,10 +175,10 @@ def test_complicated_with():
 
 def test_resolving_with_clauses_with_columns():
     query = """
-    WITH 
+    WITH
     query1 (c1, c2) AS (SELECT * FROM t2),
-    query2 (c3, c4) AS (SELECT c5, c6 FROM t4) 
-    SELECT query1.c2, query2.c4 
+    query2 (c3, c4) AS (SELECT c5, c6 FROM t4)
+    SELECT query1.c2, query2.c4
     FROM query1 left join query2 on query1.c1 = query2.c3
     order by query1.c2;
     """
@@ -207,10 +207,10 @@ def test_resolving_with_clauses_with_columns():
 
 def test_resolving_with_columns():
     query = """
-    WITH 
+    WITH
     query1 AS (SELECT c1, c2 FROM t5),
-    query2 AS (SELECT c3, c4 FROM t6) 
-    SELECT query1.c2, query2.c4 
+    query2 AS (SELECT c3, c4 FROM t6)
+    SELECT query1.c2, query2.c4
     FROM query1 left join query2 on query1.c1 = query2.c3
     order by query1.c2;
     """
@@ -223,7 +223,7 @@ def test_resolving_with_columns():
     assert parser.tables == ["t5", "t6"]
     assert parser.columns_aliases == {}
     assert parser.columns_aliases_names == []
-    assert parser.columns_aliases_dict == None
+    assert parser.columns_aliases_dict is None
     assert parser.columns == ["c1", "c2", "c3", "c4"]
     assert parser.columns_dict == {
         "join": ["c1", "c3"],
@@ -235,10 +235,10 @@ def test_resolving_with_columns():
 
 def test_resolving_with_columns_with_wildcard():
     query = """
-    WITH 
+    WITH
     query1 AS (SELECT c1, c2, c4 FROM t5),
-    query2 AS (SELECT c3, c7 FROM t6) 
-    SELECT query1.*, query2.c7 
+    query2 AS (SELECT c3, c7 FROM t6)
+    SELECT query1.*, query2.c7
     FROM query1 left join query2 on query1.c4 = query2.c3
     order by query2.c7;
     """
@@ -262,10 +262,10 @@ def test_resolving_with_columns_with_wildcard():
 
 def test_resolving_with_columns_with_nested_tables_prefixes():
     query = """
-    WITH 
+    WITH
     query1 AS (SELECT t5.c1, t5.c2, t6.c4 FROM t5 left join t6 on t5.link1=t6.link2),
-    query2 AS (SELECT c3, c7 FROM t7 union all select c4, c12 from t8) 
-    SELECT query1.*, query2.c7, query2.c3 
+    query2 AS (SELECT c3, c7 FROM t7 union all select c4, c12 from t8)
+    SELECT query1.*, query2.c7, query2.c3
     FROM query1 left join query2 on query1.c4 = query2.c3
     order by query2.c7;
     """
@@ -310,7 +310,7 @@ def test_resolving_with_columns_with_nested_tables_prefixes():
 
 def test_nested_with_statement_in_create_table():
     qry = """
-            CREATE table xyz as 
+            CREATE table xyz as
             with sub as (select it_id from internal_table)
             SELECT *
             from (