Repository: PennyLaneAI/pennylane-rigetti (language: python)

Issue:
Missing comma(s) causes an error
# Intro

First off, thanks _very_ much for this great plugin, it's really exciting.

I've run into a bug when trying to use the latest versions. Because [`requirements.txt`](https://github.com/PennyLaneAI/pennylane-rigetti/blob/master/requirements.txt#L3), [`setup.py`](https://github.com/PennyLaneAI/pennylane-rigetti/blob/master/setup.py#L10), or both are missing a comma between the lower and upper bounds in `qcs-api-client>=0.20.13<0.22.0`, I get an `AttributeError` and a couple of other friends. I think putting that comma in should fix the issue; I'll put up a PR shortly.

Thanks again!

# Reproducing the error

## Setup
```shell
~/tmp/reprex $ python -mvenv venv 
~/tmp/reprex $ source venv/bin/activate
(venv) ~/tmp/reprex $ pip install -U -qqq pip setuptools wheel Pennylane Pennylane-Rigetti
(venv) ~/tmp/reprex $ pip freeze
anyio==3.6.2
appdirs==1.4.4
attrs==21.4.0
autograd==1.5
autoray==0.6.0
cachetools==5.3.0
certifi==2022.12.7
charset-normalizer==3.0.1
decorator==5.1.1
future==0.18.3
h11==0.14.0
httpcore==0.16.3
httpx==0.23.3
idna==3.4
iso8601==1.1.0
lark==0.11.3
msgpack==0.6.2
networkx==2.8.8
ninja==1.11.1
numpy==1.23.5
PennyLane==0.28.0
PennyLane-Lightning==0.28.2
PennyLane-Rigetti==0.27.0
py==1.11.0
pydantic==1.10.4
PyJWT==2.6.0
pyquil==3.3.3
python-dateutil==2.8.2
python-rapidjson==1.9
pyzmq==25.0.0
qcs-api-client==0.21.3
requests==2.28.2
retry==0.9.2
retrying==1.3.4
retworkx==0.12.1
rfc3339==6.2
rfc3986==1.5.0
rpcq==3.10.0
ruamel.yaml==0.17.21
ruamel.yaml.clib==0.2.7
rustworkx==0.12.1
scipy==1.10.0
semantic-version==2.10.0
six==1.16.0
sniffio==1.3.0
toml==0.10.2
types-python-dateutil==2.8.19.6
types-retry==0.9.9.1
typing_extensions==4.4.0
urllib3==1.26.14
```

## Error

```python
>>> import pennylane as qml
>>> qml.device("rigetti.qpu", device="Aspen-M-2")
Traceback (most recent call last):
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3030, in _dep_map
    return self.__dep_map
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 2826, in __getattr__
    raise AttributeError(attr)
AttributeError: _DistInfoDistribution__dep_map

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 35, in __init__
    parsed = parse_requirement(requirement_string)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py", line 64, in parse_requirement
    return _parse_requirement(Tokenizer(source, rules=DEFAULT_RULES))
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py", line 82, in _parse_requirement
    url, specifier, marker = _parse_requirement_details(tokenizer)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py", line 120, in _parse_requirement_details
    specifier = _parse_specifier(tokenizer)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py", line 206, in _parse_specifier
    with tokenizer.enclosing_tokens("LEFT_PARENTHESIS", "RIGHT_PARENTHESIS"):
  File "/Users/genos/.pyenv/versions/3.10.7/lib/python3.10/contextlib.py", line 142, in __exit__
    next(self.gen)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_tokenizer.py", line 183, in enclosing_tokens
    self.raise_syntax_error(
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_tokenizer.py", line 163, in raise_syntax_error
    raise ParserSyntaxError(
pkg_resources.extern.packaging._tokenizer.ParserSyntaxError: Expected closing RIGHT_PARENTHESIS
    qcs-api-client (>=0.20.13<0.22.0)
                   ~~~~~~~~~~^

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pennylane/__init__.py", line 316, in device
    plugin_device_class = plugin_devices[name].load()
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 2467, in load
    self.require(*args, **kwargs)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 2489, in require
    reqs = self.dist.requires(self.extras)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 2746, in requires
    dm = self._dep_map
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3032, in _dep_map
    self.__dep_map = self._compute_dependencies()
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3042, in _compute_dependencies
    reqs.extend(parse_requirements(req))
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/__init__.py", line 3095, in __init__
    super(Requirement, self).__init__(requirement_string)
  File "/Users/genos/tmp/reprex/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 37, in __init__
    raise InvalidRequirement(str(e)) from e
pkg_resources.extern.packaging.requirements.InvalidRequirement: Expected closing RIGHT_PARENTHESIS
    qcs-api-client (>=0.20.13<0.22.0)
                   ~~~~~~~~~~^
```


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml
index 12de6f50..981c6461 100644
--- a/.github/workflows/format.yml
+++ b/.github/workflows/format.yml
@@ -1,26 +1,26 @@
-name: Formatting check
-on:
-- pull_request
-
-jobs:
-  black:
-    runs-on: ubuntu-latest
-
-    steps:
-      - name: Cancel Previous Runs
-        uses: styfle/cancel-workflow-action@0.4.1
-        with:
-          access_token: ${{ github.token }}
-
-      - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: 3.8
-
-      - name: Install dependencies
-        run: pip install black
-
-      - uses: actions/checkout@v2
-
-      - name: Run Black
-        run: black -l 100 pennylane_rigetti/ --check
+name: Formatting check
+on:
+- pull_request
+
+jobs:
+  black:
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Cancel Previous Runs
+        uses: styfle/cancel-workflow-action@0.4.1
+        with:
+          access_token: ${{ github.token }}
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.8
+
+      - name: Install dependencies
+        run: pip install black
+
+      - uses: actions/checkout@v2
+
+      - name: Run Black
+        run: black -l 100 pennylane_rigetti/ --check
diff --git a/.github/workflows/post_release_version_bump.yml b/.github/workflows/post_release_version_bump.yml
index 9fcf2c16..56004f71 100644
--- a/.github/workflows/post_release_version_bump.yml
+++ b/.github/workflows/post_release_version_bump.yml
@@ -20,7 +20,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install pennylane
+          pip install -r requirements.txt
 
       - name: Run version bump
         run: >
diff --git a/.github/workflows/pre_release_version_bump.yml b/.github/workflows/pre_release_version_bump.yml
index 190d846a..1ac68282 100644
--- a/.github/workflows/pre_release_version_bump.yml
+++ b/.github/workflows/pre_release_version_bump.yml
@@ -10,6 +10,7 @@ jobs:
     steps:
       - name: Clone repository
         uses: actions/checkout@v2
+
       - name: Install Python
         uses: actions/setup-python@v2
         with:
@@ -18,7 +19,7 @@ jobs:
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
-          pip install pennylane
+          pip install -r requirements.txt
 
       - name: Run version bump
         run: >
diff --git a/.github/workflows/upload.yml b/.github/workflows/upload.yml
index 739f268f..e80f9838 100644
--- a/.github/workflows/upload.yml
+++ b/.github/workflows/upload.yml
@@ -1,41 +1,36 @@
-name: Upload
-on:
-  release:
-    types: [published]
-
-jobs:
-  upload:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-
-      - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: 3.8
-
-      - name: Run Forest Quilc
-        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.22.0 -R
-
-      - name: Run Forest QVM
-        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
-
-      - name: Build and install Plugin
-        run: |
-          python -m pip install --upgrade pip wheel
-          python setup.py bdist_wheel
-          pip install dist/PennyLane*.whl
-
-      - name: Install test dependencies
-        run: |
-          pip install wheel pytest pytest-cov pytest-mock flaky --upgrade
-
-      - name: Run tests
-        run: |
-          python -m pytest tests --tb=native
-
-      - name: Publish
-        uses: pypa/gh-action-pypi-publish@master
-        with:
-          user: __token__
-          password: ${{ secrets.PYPI }}
+name: Upload
+on:
+  release:
+    types: [published]
+
+jobs:
+  upload:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.8
+
+      - name: Run Forest Quilc
+        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.23.0 -R
+
+      - name: Run Forest QVM
+        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
+
+      - name: Install plugin and test dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install '.[test]'
+
+      - name: Run tests
+        run: |
+          python -m pytest tests --tb=native
+
+      - name: Publish
+        uses: pypa/gh-action-pypi-publish@master
+        with:
+          user: __token__
+          password: ${{ secrets.PYPI }}
diff --git a/.gitignore b/.gitignore
index 16442955..23a16b73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@ notebooks/*
 .pytest_cache/*
 .vscode/*
 doc/code/api/*
+.eggs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5e481e7..df8f2935 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@
 
 ### Breaking changes
 
+* Build dependency specification is now solely in `requirements.txt`, which is read
+  by `setup.py`. What's more, a missing comma has been added to the version bounds
+  on `qcs-api-client`, fixing ([#120](https://github.com/PennyLaneAI/pennylane-rigetti/pull/120))
+  a bug ([#119](https://github.com/PennyLaneAI/pennylane-rigetti/issues/119)) that
+  was causing errors when trying to use the package.
+
 * `pennylane-rigetti` no longer supports `python3.7`. A newer python version is required.
   [(#121)](https://github.com/PennyLaneAI/pennylane-rigetti/pull/121)
 
@@ -21,6 +27,7 @@
 This release contains contributions from (in alphabetical order):
 
 Albert Mitjans Coma
+Graham Enos
 
 ---
 
diff --git a/requirements.txt b/requirements.txt
index ac5746e2..d62ddf90 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
-pyquil>=3.0.0,<4.0.0
+numpy>=1.21,<1.24
+networkx>=2.5,<3.0
 pennylane>=0.18
-qcs-api-client>=0.20.13<0.22.0
-networkx
-flaky
+pyquil>=3.0.0,<4.0.0
+qcs-api-client>=0.20.13,<0.22.0
diff --git a/setup.py b/setup.py
index 81727c00..51e05ae7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,60 +1,64 @@
-#!/usr/bin/env python3
-import os
-import sys
-
-from setuptools import setup
-
-with open("pennylane_rigetti/_version.py") as f:
-    version = f.readlines()[-1].split()[-1].strip("\"'")
-
-
-requirements = ["pyquil>=3.0.0,<4.0.0", "qcs-api-client>=0.20.13<0.22.0", "pennylane>=0.18"]
-
-info = {
-    "name": "PennyLane-Rigetti",
-    "version": version,
-    "maintainer": "Xanadu Inc.",
-    "maintainer_email": "software@xanadu.ai",
-    "url": "https://github.com/PennyLaneAI/pennylane-rigetti",
-    "license": "BSD 3-Clause",
-    "packages": ["pennylane_rigetti"],
-    "entry_points": {
-        "pennylane.plugins": [
-            "rigetti.qvm = pennylane_rigetti:QVMDevice",
-            "rigetti.qpu = pennylane_rigetti:QPUDevice",
-            "rigetti.wavefunction = pennylane_rigetti:WavefunctionDevice",
-            "rigetti.numpy_wavefunction = pennylane_rigetti:NumpyWavefunctionDevice",
-        ],
-        "pennylane.io": [
-            "pyquil_program = pennylane_rigetti:load_program",
-            "quil = pennylane_rigetti:load_quil",
-            "quil_file = pennylane_rigetti:load_quil_from_file",
-        ],
-    },
-    "description": "Rigetti backend for the PennyLane library",
-    "long_description": open("README.rst").read(),
-    "provides": ["pennylane_rigetti"],
-    "install_requires": requirements,
-    "long_description_content_type": "text/x-rst",
-}
-
-classifiers = [
-    "Development Status :: 4 - Beta",
-    "Environment :: Console",
-    "Intended Audience :: Science/Research",
-    "License :: OSI Approved :: BSD License",
-    "Natural Language :: English",
-    "Operating System :: POSIX",
-    "Operating System :: MacOS :: MacOS X",
-    "Operating System :: POSIX :: Linux",
-    "Operating System :: Microsoft :: Windows",
-    "Programming Language :: Python",
-    "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
-    "Programming Language :: Python :: 3 :: Only",
-    "Topic :: Scientific/Engineering :: Physics",
-]
-
-setup(classifiers=classifiers, **(info))
+#!/usr/bin/env python3
+from pathlib import Path
+from setuptools import setup
+
+_here = Path(__file__).parent
+
+with open(_here / "pennylane_rigetti" / "_version.py") as f:
+    version = f.readlines()[-1].split()[-1].strip("\"'")
+
+with open(_here / "requirements.txt") as f:
+    requirements = [req.strip() for req in f.readlines()]
+
+with open(_here / "requirements-test.txt") as f:
+    test_requirements = [req.strip() for req in f.readlines()]
+
+info = {
+    "name": "PennyLane-Rigetti",
+    "version": version,
+    "maintainer": "Xanadu Inc.",
+    "maintainer_email": "software@xanadu.ai",
+    "url": "https://github.com/PennyLaneAI/pennylane-rigetti",
+    "license": "BSD 3-Clause",
+    "packages": ["pennylane_rigetti"],
+    "entry_points": {
+        "pennylane.plugins": [
+            "rigetti.qvm = pennylane_rigetti:QVMDevice",
+            "rigetti.qpu = pennylane_rigetti:QPUDevice",
+            "rigetti.wavefunction = pennylane_rigetti:WavefunctionDevice",
+            "rigetti.numpy_wavefunction = pennylane_rigetti:NumpyWavefunctionDevice",
+        ],
+        "pennylane.io": [
+            "pyquil_program = pennylane_rigetti:load_program",
+            "quil = pennylane_rigetti:load_quil",
+            "quil_file = pennylane_rigetti:load_quil_from_file",
+        ],
+    },
+    "description": "Rigetti backend for the PennyLane library",
+    "long_description": open("README.rst").read(),
+    "provides": ["pennylane_rigetti"],
+    "install_requires": requirements,
+    "extras_require": {"test": test_requirements},
+    "long_description_content_type": "text/x-rst",
+}
+
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "Environment :: Console",
+    "Intended Audience :: Science/Research",
+    "License :: OSI Approved :: BSD License",
+    "Natural Language :: English",
+    "Operating System :: POSIX",
+    "Operating System :: MacOS :: MacOS X",
+    "Operating System :: POSIX :: Linux",
+    "Operating System :: Microsoft :: Windows",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3 :: Only",
+    "Topic :: Scientific/Engineering :: Physics",
+]
+
+setup(classifiers=classifiers, **(info))


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 7de9ab56..d0eae2f5 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -1,99 +1,87 @@
-name: Tests
-on:
-  push:
-    branches:
-      - master
-  pull_request:
-
-jobs:
-  tests:
-    runs-on: ubuntu-latest
-
-    strategy:
-      matrix:
-        python-version: ["3.8", "3.10"]
-
-    steps:
-      - name: Cancel Previous Runs
-        uses: styfle/cancel-workflow-action@0.4.1
-        with:
-          access_token: ${{ github.token }}
-
-      - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: ${{ matrix.python-version }}
-
-      - name: Run Forest Quilc
-        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.23.0 -R
-
-      - name: Run Forest QVM
-        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
-
-      - uses: actions/checkout@v2
-
-      - name: Install requirements
-        run: |
-          python -m pip install --upgrade pip
-          pip install -r requirements.txt
-          pip install wheel pytest pytest-cov pytest-mock flaky --upgrade
-
-      - name: Install Plugin
-        run: |
-          python setup.py bdist_wheel
-          pip install dist/PennyLane*.whl
-
-      - name: Run tests
-        run: python -m pytest tests --cov=pennylane_rigetti --cov-report=term-missing --cov-report=xml -p no:warnings --tb=native
-
-      - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v1.0.7
-        with:
-          file: ./coverage.xml
-
-  integration-tests:
-    runs-on: ubuntu-latest
-
-    strategy:
-      matrix:
-        python-version: ["3.8", "3.10"]
-
-    steps:
-      - name: Cancel Previous Runs
-        uses: styfle/cancel-workflow-action@0.4.1
-        with:
-          access_token: ${{ github.token }}
-
-      - name: Run Forest Quilc
-        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.23.0 -R
-
-      - name: Run Forest QVM
-        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
-
-      - uses: actions/checkout@v2
-
-      - name: Set up Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: ${{ matrix.python-version }}
-
-      - name: Install requirements
-        run: |
-          python -m pip install --upgrade pip
-          pip install -r requirements.txt
-          pip install wheel pytest pytest-cov pytest-mock flaky --upgrade
-
-      - name: Install Plugin
-        run: |
-          python setup.py bdist_wheel
-          pip install dist/PennyLane*.whl
-
-      - name: Run tests
-        run: |
-          pl-device-test --device=rigetti.numpy_wavefunction --tb=short --skip-ops --analytic=True
-          pl-device-test --device=rigetti.wavefunction --tb=short --skip-ops --analytic=False --shots=20000
-
-      - name: Upload coverage to Codecov
-        uses: codecov/codecov-action@v1.0.7
-        with:
-          file: ./coverage.xml
+name: Tests
+on:
+  push:
+    branches:
+      - master
+  pull_request:
+
+jobs:
+  tests:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        python-version: ["3.8", "3.10"]
+
+    steps:
+      - name: Cancel Previous Runs
+        uses: styfle/cancel-workflow-action@0.4.1
+        with:
+          access_token: ${{ github.token }}
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+
+      - name: Run Forest Quilc
+        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.23.0 -R
+
+      - name: Run Forest QVM
+        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
+
+      - uses: actions/checkout@v2
+
+      - name: Install plugin and test requirements
+        run: |
+          python -m pip install --upgrade pip
+          pip install '.[test]'
+
+      - name: Run tests
+        run: python -m pytest tests --cov=pennylane_rigetti --cov-report=term-missing --cov-report=xml -p no:warnings --tb=native
+
+      - name: Upload coverage to Codecov
+        uses: codecov/codecov-action@v1.0.7
+        with:
+          file: ./coverage.xml
+
+  integration-tests:
+    runs-on: ubuntu-latest
+
+    strategy:
+      matrix:
+        python-version: ["3.8", "3.10"]
+
+    steps:
+      - name: Cancel Previous Runs
+        uses: styfle/cancel-workflow-action@0.4.1
+        with:
+          access_token: ${{ github.token }}
+
+      - name: Run Forest Quilc
+        run: docker run --rm -d -p 5555:5555 rigetti/quilc:1.23.0 -R
+
+      - name: Run Forest QVM
+        run: docker run --rm -d -p 5000:5000 rigetti/qvm -S
+
+      - uses: actions/checkout@v2
+
+      - name: Set up Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: ${{ matrix.python-version }}
+
+      - name: Install plugin and test requirements
+        run: |
+          python -m pip install --upgrade pip
+          pip install '.[test]'
+
+      - name: Run tests
+        run: |
+          pl-device-test --device=rigetti.numpy_wavefunction --tb=short --skip-ops --analytic=True
+          pl-device-test --device=rigetti.wavefunction --tb=short --skip-ops --analytic=False --shots=20000
+
+      - name: Upload coverage to Codecov
+        uses: codecov/codecov-action@v1.0.7
+        with:
+          file: ./coverage.xml
diff --git a/requirements-test.txt b/requirements-test.txt
new file mode 100644
index 00000000..b83224df
--- /dev/null
+++ b/requirements-test.txt
@@ -0,0 +1,5 @@
+flaky>=3.7.0
+pytest>=7.2.1
+pytest-cov>=4.0.0
+pytest-mock>=3.10.0
+wheel>=0.38.4