diff --git a/news/163.bugfix.rst b/news/163.bugfix.rst
new file mode 100644
index 0000000..5ad4e4f
--- /dev/null
+++ b/news/163.bugfix.rst
@@ -0,0 +1,1 @@
+Added support to the AST parser for discovering non-standard invocations of ``setup`` in ``setup.py``, e.g. using the fully qualified function name.
diff --git a/src/requirementslib/models/setup_info.py b/src/requirementslib/models/setup_info.py
index b3251f7..4888169 100644
--- a/src/requirementslib/models/setup_info.py
+++ b/src/requirementslib/models/setup_info.py
@@ -665,13 +665,31 @@ def ast_unparse(item, initial_mapping=False, analyzer=None, recurse=True):  # no
             unparsed = item
     elif six.PY3 and isinstance(item, ast.NameConstant):
         unparsed = item.value
+    elif isinstance(item, ast.Attribute):
+        attr_name = getattr(item, "value", None)
+        attr_attr = getattr(item, "attr", None)
+        name = unparse(attr_name) if attr_name is not None else attr_attr
+        if initial_mapping:
+            unparsed = item
+        elif name and attr_attr:
+            if not initial_mapping and isinstance(name, six.string_types):
+                unparsed = ".".join([item for item in (name, attr_attr) if item])
+            else:
+                unparsed = item
+        elif attr_attr and not name:
+            unparsed = attr_attr
+        else:
+            unparsed = name
     elif isinstance(item, ast.Call):
         unparsed = {}
         if isinstance(item.func, ast.Name):
-            name = unparse(item.func)
-            unparsed[name] = {}
+            func_name = unparse(item.func)
+        elif isinstance(item.func, ast.Attribute):
+            func_name = unparse(item.func)
+        if func_name:
+            unparsed[func_name] = {}
             for keyword in item.keywords:
-                unparsed[name].update(unparse(keyword))
+                unparsed[func_name].update(unparse(keyword))
     elif isinstance(item, ast.keyword):
         unparsed = {unparse(item.arg): unparse(item.value)}
     elif isinstance(item, ast.Assign):
@@ -712,7 +730,14 @@ def ast_parse_setup_py(path):
     ast_analyzer.visit(tree)
     setup = {}  # type: Dict[Any, Any]
     for k, v in ast_analyzer.function_map.items():
-        if isinstance(k, ast.Name) and k.id == "setup":
+        fn_name = ""
+        if isinstance(k, ast.Name):
+            fn_name = k.id
+        elif isinstance(k, ast.Attribute):
+            fn = ast_unparse(k)
+            if isinstance(fn, six.string_types):
+                _, _, fn_name = fn.rpartition(".")
+        if fn_name == "setup":
             setup = v
     cleaned_setup = ast_unparse(setup, analyzer=ast_analyzer)
     return cleaned_setup

AST parsing fails when setup.py is called with fully qualified functions
`setuptools.setup()` for example is not captured by the AST parser, but it should be
diff --git a/tests/conftest.py b/tests/conftest.py
index a9f87b8..209831b 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -12,6 +12,8 @@ import vistir
 import requirementslib.utils
 from requirementslib.models.setup_info import SetupInfo
 
+CURRENT_FILE = vistir.compat.Path(__file__).absolute()
+
 
 def check_for_mercurial():
     c = vistir.misc.run(
@@ -120,6 +122,21 @@ def artifact_dir():
     )
 
 
+@pytest.fixture(scope="session")
+def fixture_dir():
+    return CURRENT_FILE.parent.joinpath("fixtures")
+
+
+@pytest.fixture(scope="session")
+def setup_py_dir(fixture_dir):
+    return fixture_dir / "setup_py"
+
+
+@pytest.fixture(scope="session")
+def setup_cfg_dir(fixture_dir):
+    return fixture_dir / "setup_cfg"
+
+
 @pytest.fixture
 def test_artifact(artifact_dir, pathlib_tmpdir, request):
     name = request.param["name"]
diff --git a/tests/fixtures/setup_py/package_using_fully_qualified_setuptools/setup.py b/tests/fixtures/setup_py/package_using_fully_qualified_setuptools/setup.py
new file mode 100644
index 0000000..e388b00
--- /dev/null
+++ b/tests/fixtures/setup_py/package_using_fully_qualified_setuptools/setup.py
@@ -0,0 +1,22 @@
+import os
+
+import setuptools
+
+thisdir = os.path.abspath(os.path.dirname(__file__))
+version = "1.0.0"
+
+testing_extras = ["coverage", "flaky"]
+
+setuptools.setup(
+    name="test_package",
+    version=version,
+    description="The Backend HTTP Server",
+    long_description="This is a package",
+    install_requires=["six"],
+    tests_require=testing_extras,
+    extras_require={"testing": testing_extras},
+    package_dir={"": "src"},
+    packages=["test_package"],
+    include_package_data=True,
+    zip_safe=False,
+)
diff --git a/tests/fixtures/setup_py/package_using_fully_qualified_setuptools/src/test_package/__init__.py b/tests/fixtures/setup_py/package_using_fully_qualified_setuptools/src/test_package/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/setup_py/package_with_extras_as_variable/setup.py b/tests/fixtures/setup_py/package_with_extras_as_variable/setup.py
new file mode 100644
index 0000000..21d5301
--- /dev/null
+++ b/tests/fixtures/setup_py/package_with_extras_as_variable/setup.py
@@ -0,0 +1,22 @@
+import os
+
+from setuptools import find_packages, setup
+
+thisdir = os.path.abspath(os.path.dirname(__file__))
+version = "1.0.0"
+
+testing_extras = ["coverage", "flaky"]
+
+setup(
+    name="test_package",
+    version=version,
+    description="The Backend HTTP Server",
+    long_description="This is a package",
+    install_requires=["six"],
+    tests_require=testing_extras,
+    extras_require={"testing": testing_extras},
+    package_dir={"": "src"},
+    packages=["test_package"],
+    include_package_data=True,
+    zip_safe=False,
+)
diff --git a/tests/fixtures/setup_py/package_with_extras_as_variable/src/test_package/__init__.py b/tests/fixtures/setup_py/package_with_extras_as_variable/src/test_package/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/setup_py/package_with_multiple_extras/setup.py b/tests/fixtures/setup_py/package_with_multiple_extras/setup.py
new file mode 100644
index 0000000..bdae619
--- /dev/null
+++ b/tests/fixtures/setup_py/package_with_multiple_extras/setup.py
@@ -0,0 +1,22 @@
+import os
+
+from setuptools import find_packages, setup
+
+thisdir = os.path.abspath(os.path.dirname(__file__))
+version = "1.0.0"
+
+testing_extras = ["coverage", "flaky"]
+
+setup(
+    name="test_package",
+    version=version,
+    description="The Backend HTTP Server",
+    long_description="This is a package",
+    install_requires=["six"],
+    tests_require=testing_extras,
+    extras_require={"testing": testing_extras, "dev": ["parver", "invoke", "wheel"]},
+    package_dir={"": "src"},
+    packages=["test_package"],
+    include_package_data=True,
+    zip_safe=False,
+)
diff --git a/tests/fixtures/setup_py/package_with_multiple_extras/src/test_package/__init__.py b/tests/fixtures/setup_py/package_with_multiple_extras/src/test_package/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/setup_py/package_with_one_extra/setup.py b/tests/fixtures/setup_py/package_with_one_extra/setup.py
new file mode 100644
index 0000000..21d5301
--- /dev/null
+++ b/tests/fixtures/setup_py/package_with_one_extra/setup.py
@@ -0,0 +1,22 @@
+import os
+
+from setuptools import find_packages, setup
+
+thisdir = os.path.abspath(os.path.dirname(__file__))
+version = "1.0.0"
+
+testing_extras = ["coverage", "flaky"]
+
+setup(
+    name="test_package",
+    version=version,
+    description="The Backend HTTP Server",
+    long_description="This is a package",
+    install_requires=["six"],
+    tests_require=testing_extras,
+    extras_require={"testing": testing_extras},
+    package_dir={"": "src"},
+    packages=["test_package"],
+    include_package_data=True,
+    zip_safe=False,
+)
diff --git a/tests/fixtures/setup_py/package_with_one_extra/src/test_package/__init__.py b/tests/fixtures/setup_py/package_with_one_extra/src/test_package/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit/test_setup_info.py b/tests/unit/test_setup_info.py
index f4dde47..2fb825b 100644
--- a/tests/unit/test_setup_info.py
+++ b/tests/unit/test_setup_info.py
@@ -1,6 +1,7 @@
 # -*- coding=utf-8 -*-
 
 import os
+import shutil
 import sys
 
 import pip_shims.shims
@@ -8,6 +9,7 @@ import pytest
 import vistir
 
 from requirementslib.models.requirements import Requirement
+from requirementslib.models.setup_info import ast_parse_setup_py
 
 
 @pytest.mark.parametrize(
@@ -124,52 +126,25 @@ setup(
         assert sorted(list(setup_dict.get("requires").keys())) == ["raven"]
 
 
-def test_extras(pathlib_tmpdir):
+@pytest.mark.parametrize(
+    "setup_py_name, extras, dependencies",
+    [
+        (
+            "package_with_multiple_extras",
+            ["testing", "dev"],
+            ["coverage", "flaky", "invoke", "parver", "six", "wheel"],
+        ),
+        ("package_with_one_extra", ["testing"], ["coverage", "flaky", "six"]),
+    ],
+)
+def test_extras(pathlib_tmpdir, setup_py_dir, setup_py_name, extras, dependencies):
     """Test named extras as a dependency"""
     setup_dir = pathlib_tmpdir.joinpath("test_package")
-    setup_dir.mkdir()
+    shutil.copytree(setup_py_dir.joinpath(setup_py_name).as_posix(), setup_dir.as_posix())
     assert setup_dir.is_dir()
-    setup_py = setup_dir.joinpath("setup.py")
-    setup_py.write_text(
-        u"""
-import os
-from setuptools import setup, find_packages
-
-thisdir = os.path.abspath(os.path.dirname(__file__))
-version = "1.0.0"
-
-testing_extras = [
-    'coverage',
-    'flaky',
-]
-
-setup(
-    name='test_package',
-    version=version,
-    description="The Backend HTTP Server",
-    long_description="This is a package",
-    install_requires=[
-        'six',
-    ],
-    tests_require=testing_extras,
-    extras_require={
-        'testing': testing_extras,
-    },
-    package_dir={"": "src"},
-    packages=['test_package'],
-    include_package_data=True,
-    zip_safe=False,
-)
-    """.strip()
-    )
-    src_dir = setup_dir.joinpath("src")
-    src_dir.mkdir()
-    pkg_dir = src_dir.joinpath("test_package")
-    pkg_dir.mkdir()
-    pkg_dir.joinpath("__init__.py").write_text(u"")
     pipfile_entry = {
         "path": "./{0}".format(setup_dir.name),
-        "extras": ["testing"],
+        "extras": extras,
         "editable": True,
     }
     setup_dict = None
@@ -178,8 +153,56 @@ setup(
         assert r.name == "test-package"
         r.req.setup_info.get_info()
         setup_dict = r.req.setup_info.as_dict()
-        assert sorted(list(setup_dict.get("requires").keys())) == [
-            "coverage",
-            "flaky",
-            "six",
-        ], setup_dict
+        assert sorted(list(setup_dict.get("requires").keys())) == dependencies
+
+
+def test_ast_parser_finds_variables(setup_py_dir):
+    parsed = ast_parse_setup_py(
+        setup_py_dir.joinpath("package_with_extras_as_variable/setup.py").as_posix()
+    )
+    expected = {
+        "name": "test_package",
+        "version": "1.0.0",
+        "description": "The Backend HTTP Server",
+        "long_description": "This is a package",
+        "install_requires": ["six"],
+        "tests_require": ["coverage", "flaky"],
+        "extras_require": {"testing": ["coverage", "flaky"]},
+        "package_dir": {"": "src"},
+        "packages": ["test_package"],
+        "include_package_data": True,
+        "zip_safe": False,
+    }
+    for k, v in expected.items():
+        assert k in parsed
+        if isinstance(v, bool):
+            assert str(parsed[k]) == str(v), parsed[k]
+        else:
+            assert parsed[k] == v, parsed[k]
+
+
+def test_ast_parser_finds_fully_qualified_setup(setup_py_dir):
+    parsed = ast_parse_setup_py(
+        setup_py_dir.joinpath(
+            "package_using_fully_qualified_setuptools/setup.py"
+        ).as_posix()
+    )
+    expected = {
+        "name": "test_package",
+        "version": "1.0.0",
+        "description": "The Backend HTTP Server",
+        "long_description": "This is a package",
+        "install_requires": ["six"],
+        "tests_require": ["coverage", "flaky"],
+        "extras_require": {"testing": ["coverage", "flaky"]},
+        "package_dir": {"": "src"},
+        "packages": ["test_package"],
+        "include_package_data": True,
+        "zip_safe": False,
+    }
+    for k, v in expected.items():
+        assert k in parsed
+        if isinstance(v, bool):
+            assert str(parsed[k]) == str(v), parsed[k]
+        else:
+            assert parsed[k] == v, parsed[k]

pip install -e .[dev,tests,typing]
parse_log_pytest
requirements.txt
pytest
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
appdirs==1.4.4
Arpeggio==1.10.2
attrs==22.2.0
black==22.8.0
bleach==4.1.0
cached-property==1.5.2
Cerberus==1.3.5
certifi==2021.5.30
cffi==1.15.1
cfgv==3.3.1
charset-normalizer==2.0.12
click==8.0.4
click-default-group==1.2.4
cmarkgfm==2024.11.20
colorama==0.4.5
coverage==4.5.4
cryptography==40.0.2
dataclasses==0.8
decorator==4.4.2
distlib==0.3.9
docutils==0.18.1
execnet==1.9.0
filelock==3.4.1
findimports==2.2.0
first==2.0.2
flake8==5.0.4
flake8-bugbear==22.9.23
identify==2.4.4
idna==3.10
importlab==0.8.1
importlib-metadata==4.2.0
importlib-resources==5.2.3
incremental==22.10.0
iniconfig==1.1.1
invoke==2.2.0
isort==5.10.1
jeepney==0.7.1
Jinja2==3.0.3
keyring==23.4.1
libcst==0.4.1
lxml==5.3.1
MarkupSafe==2.0.1
mccabe==0.7.0
MonkeyType==22.2.0
mypy==0.971
mypy-extensions==1.0.0
mypytools==0.1.15
networkx==2.5.1
ninja==1.11.1.1
nodeenv==1.6.0
orderedmultidict==1.0.1
packaging==21.3
parver==0.3.1
pathspec==0.9.0
pep517==0.13.1
pip-shims==0.7.3
pkginfo==1.10.0
platformdirs==2.4.0
plette==0.2.3
pluggy==1.0.0
pre-commit==2.17.0
py==1.11.0
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.14.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==2.10.1
pytest-sugar==0.9.6
pytest-timeout==2.1.0
pytest-xdist==3.0.2
pytype==2022.1.5
PyYAML==6.0.1
readme-renderer==34.0
requests==2.27.1
requests-toolbelt==1.0.0
-e git+https://github.com/sarugaku/requirementslib.git@969f2aeed4efcd918eaa40f4a4662743eb722091#egg=requirementslib
rfc3986==1.5.0
rope==1.1.1
SecretStorage==3.3.3
six==1.17.0
tabulate==0.8.10
termcolor==1.1.0
toml==0.10.2
tomli==1.2.3
tomlkit==0.11.6
towncrier==21.9.0
tqdm==4.64.1
twine==3.8.0
typed-ast==1.5.5
typing==3.7.4.3
typing-inspect==0.9.0
typing_extensions==4.1.1
urllib3==1.26.20
virtualenv==20.16.2
vistir==0.5.6
vulture==2.8
watchdog==2.3.1
webencodings==0.5.1
zipp==3.6.0

name: requirementslib
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - appdirs==1.4.4
      - arpeggio==1.10.2
      - attrs==22.2.0
      - black==22.8.0
      - bleach==4.1.0
      - cached-property==1.5.2
      - cerberus==1.3.5
      - cffi==1.15.1
      - cfgv==3.3.1
      - charset-normalizer==2.0.12
      - click==8.0.4
      - click-default-group==1.2.4
      - cmarkgfm==2024.11.20
      - colorama==0.4.5
      - coverage==4.5.4
      - cryptography==40.0.2
      - dataclasses==0.8
      - decorator==4.4.2
      - distlib==0.3.9
      - docutils==0.18.1
      - execnet==1.9.0
      - filelock==3.4.1
      - findimports==2.2.0
      - first==2.0.2
      - flake8==5.0.4
      - flake8-bugbear==22.9.23
      - identify==2.4.4
      - idna==3.10
      - importlab==0.8.1
      - importlib-metadata==4.2.0
      - importlib-resources==5.2.3
      - incremental==22.10.0
      - iniconfig==1.1.1
      - invoke==2.2.0
      - isort==5.10.1
      - jeepney==0.7.1
      - jinja2==3.0.3
      - keyring==23.4.1
      - libcst==0.4.1
      - lxml==5.3.1
      - markupsafe==2.0.1
      - mccabe==0.7.0
      - monkeytype==22.2.0
      - mypy==0.971
      - mypy-extensions==1.0.0
      - mypytools==0.1.15
      - networkx==2.5.1
      - ninja==1.11.1.1
      - nodeenv==1.6.0
      - orderedmultidict==1.0.1
      - packaging==21.3
      - parver==0.3.1
      - pathspec==0.9.0
      - pep517==0.13.1
      - pip-shims==0.7.3
      - pkginfo==1.10.0
      - platformdirs==2.4.0
      - plette==0.2.3
      - pluggy==1.0.0
      - pre-commit==2.17.0
      - py==1.11.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.14.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==2.10.1
      - pytest-sugar==0.9.6
      - pytest-timeout==2.1.0
      - pytest-xdist==3.0.2
      - pytype==2022.1.5
      - pyyaml==6.0.1
      - readme-renderer==34.0
      - requests==2.27.1
      - requests-toolbelt==1.0.0
      - rfc3986==1.5.0
      - rope==1.1.1
      - secretstorage==3.3.3
      - six==1.17.0
      - tabulate==0.8.10
      - termcolor==1.1.0
      - toml==0.10.2
      - tomli==1.2.3
      - tomlkit==0.11.6
      - towncrier==21.9.0
      - tqdm==4.64.1
      - twine==3.8.0
      - typed-ast==1.5.5
      - typing==3.7.4.3
      - typing-extensions==4.1.1
      - typing-inspect==0.9.0
      - urllib3==1.26.20
      - virtualenv==20.16.2
      - vistir==0.5.6
      - vulture==2.8
      - watchdog==2.3.1
      - webencodings==0.5.1
      - zipp==3.6.0
prefix: /opt/conda/envs/requirementslib

tests/unit/test_setup_info.py::test_ast_parser_finds_fully_qualified_setup
tests/unit/test_setup_info.py::test_remote_req[https://github.com/requests/requests/archive/v2.20.1.zip-requests-requires0] tests/unit/test_setup_info.py::test_without_extras tests/unit/test_setup_info.py::test_local_req[test_artifact1] tests/unit/test_setup_info.py::test_remote_req[https://github.com/dropbox/pyannotate/archive/v1.0.4.zip-pyannotate-requires1] tests/unit/test_setup_info.py::test_extras[package_with_one_extra-extras1-dependencies1] tests/unit/test_setup_info.py::test_local_req[test_artifact0] tests/unit/test_setup_info.py::test_extras[package_with_multiple_extras-extras0-dependencies0] tests/unit/test_setup_info.py::test_no_duplicate_egg_info
tests/unit/test_setup_info.py::test_ast_parser_finds_variables
src/requirementslib/models/setup_info.py news/163.bugfix.rst
src/requirementslib/models/setup_info.py news/163.bugfix.rst