use pip-compile to pin dev requirements
diff --git a/.readthedocs.yaml b/.readthedocs.yaml
index af23210..1906952 100644
--- a/.readthedocs.yaml
+++ b/.readthedocs.yaml
@@ -1,8 +1,8 @@
 version: 2
 python:
   install:
+    - requirements: requirements/docs.txt
     - method: pip
       path: .
-    - requirements: docs/requirements.txt
 sphinx:
   builder: dirhtml
diff --git a/MANIFEST.in b/MANIFEST.in
index b130d04..8690e35 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,5 +1,6 @@
 include CHANGES.rst
 include tox.ini
+include requirements/*.txt
 graft artwork
 graft docs
 prune docs/_build
diff --git a/docs/requirements.txt b/docs/requirements.txt
deleted file mode 100644
index cfe1fd7..0000000
--- a/docs/requirements.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Sphinx~=2.1.2
-Pallets-Sphinx-Themes~=1.2.0
-sphinxcontrib-log-cabinet~=1.0.1
-sphinx-issues~=1.2.0
diff --git a/requirements/dev.in b/requirements/dev.in
new file mode 100644
index 0000000..3937d2d
--- /dev/null
+++ b/requirements/dev.in
@@ -0,0 +1,6 @@
+-e file:.
+-r docs.in
+-r tests.in
+pip-tools
+pre-commit
+tox
diff --git a/requirements/dev.txt b/requirements/dev.txt
new file mode 100644
index 0000000..b1c54e6
--- /dev/null
+++ b/requirements/dev.txt
@@ -0,0 +1,55 @@
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile requirements/dev.in
+#
+-e file:.                 # via -r requirements/dev.in, sphinx
+alabaster==0.7.12         # via sphinx
+appdirs==1.4.4            # via virtualenv
+attrs==19.3.0             # via pytest
+babel==2.8.0              # via sphinx
+certifi==2020.4.5.1       # via requests
+cfgv==3.1.0               # via pre-commit
+chardet==3.0.4            # via requests
+click==7.1.2              # via pip-tools
+distlib==0.3.0            # via virtualenv
+docutils==0.16            # via sphinx
+filelock==3.0.12          # via tox, virtualenv
+identify==1.4.15          # via pre-commit
+idna==2.9                 # via requests
+imagesize==1.2.0          # via sphinx
+more-itertools==8.3.0     # via pytest
+nodeenv==1.3.5            # via pre-commit
+packaging==20.3           # via pallets-sphinx-themes, pytest, sphinx, tox
+pallets-sphinx-themes==1.2.3  # via -r requirements/docs.in
+pip-tools==5.1.2          # via -r requirements/dev.in
+pluggy==0.13.1            # via pytest, tox
+pre-commit==2.4.0         # via -r requirements/dev.in
+py==1.8.1                 # via pytest, tox
+pygments==2.6.1           # via sphinx
+pyparsing==2.4.7          # via packaging
+pytest==5.4.2             # via -r requirements/tests.in
+pytz==2020.1              # via babel
+pyyaml==5.3.1             # via pre-commit
+requests==2.23.0          # via sphinx
+six==1.14.0               # via packaging, pip-tools, tox, virtualenv
+snowballstemmer==2.0.0    # via sphinx
+sphinx-issues==1.2.0      # via -r requirements/docs.in
+sphinx==2.4.4             # via -r requirements/docs.in, pallets-sphinx-themes, sphinx-issues, sphinxcontrib-log-cabinet
+sphinxcontrib-applehelp==1.0.2  # via sphinx
+sphinxcontrib-devhelp==1.0.2  # via sphinx
+sphinxcontrib-htmlhelp==1.0.3  # via sphinx
+sphinxcontrib-jsmath==1.0.1  # via sphinx
+sphinxcontrib-log-cabinet==1.0.1  # via -r requirements/docs.in
+sphinxcontrib-qthelp==1.0.3  # via sphinx
+sphinxcontrib-serializinghtml==1.1.4  # via sphinx
+toml==0.10.1              # via pre-commit, tox
+tox==3.15.0               # via -r requirements/dev.in
+urllib3==1.25.9           # via requests
+virtualenv==20.0.20       # via pre-commit, tox
+wcwidth==0.1.9            # via pytest
+
+# The following packages are considered to be unsafe in a requirements file:
+# pip
+# setuptools
diff --git a/requirements/docs.in b/requirements/docs.in
new file mode 100644
index 0000000..42f1651
--- /dev/null
+++ b/requirements/docs.in
@@ -0,0 +1,4 @@
+Pallets-Sphinx-Themes
+Sphinx<3
+sphinx-issues
+sphinxcontrib-log-cabinet
diff --git a/requirements/docs.txt b/requirements/docs.txt
new file mode 100644
index 0000000..14a5ad6
--- /dev/null
+++ b/requirements/docs.txt
@@ -0,0 +1,36 @@
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile requirements/docs.in
+#
+alabaster==0.7.12         # via sphinx
+babel==2.8.0              # via sphinx
+certifi==2020.4.5.1       # via requests
+chardet==3.0.4            # via requests
+docutils==0.16            # via sphinx
+idna==2.9                 # via requests
+imagesize==1.2.0          # via sphinx
+jinja2==2.11.2            # via sphinx
+markupsafe==1.1.1         # via jinja2
+packaging==20.3           # via pallets-sphinx-themes, sphinx
+pallets-sphinx-themes==1.2.3  # via -r requirements/docs.in
+pygments==2.6.1           # via sphinx
+pyparsing==2.4.7          # via packaging
+pytz==2020.1              # via babel
+requests==2.23.0          # via sphinx
+six==1.14.0               # via packaging
+snowballstemmer==2.0.0    # via sphinx
+sphinx-issues==1.2.0      # via -r requirements/docs.in
+sphinx==2.4.4             # via -r requirements/docs.in, pallets-sphinx-themes, sphinx-issues, sphinxcontrib-log-cabinet
+sphinxcontrib-applehelp==1.0.2  # via sphinx
+sphinxcontrib-devhelp==1.0.2  # via sphinx
+sphinxcontrib-htmlhelp==1.0.3  # via sphinx
+sphinxcontrib-jsmath==1.0.1  # via sphinx
+sphinxcontrib-log-cabinet==1.0.1  # via -r requirements/docs.in
+sphinxcontrib-qthelp==1.0.3  # via sphinx
+sphinxcontrib-serializinghtml==1.1.4  # via sphinx
+urllib3==1.25.9           # via requests
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/requirements/tests.in b/requirements/tests.in
new file mode 100644
index 0000000..e079f8a
--- /dev/null
+++ b/requirements/tests.in
@@ -0,0 +1 @@
+pytest
diff --git a/requirements/tests.txt b/requirements/tests.txt
new file mode 100644
index 0000000..aa2bfaf
--- /dev/null
+++ b/requirements/tests.txt
@@ -0,0 +1,15 @@
+#
+# This file is autogenerated by pip-compile
+# To update, run:
+#
+#    pip-compile requirements/tests.in
+#
+attrs==19.3.0             # via pytest
+more-itertools==8.3.0     # via pytest
+packaging==20.3           # via pytest
+pluggy==0.13.1            # via pytest
+py==1.8.1                 # via pytest
+pyparsing==2.4.7          # via packaging
+pytest==5.4.2             # via -r requirements/tests.in
+six==1.14.0               # via packaging
+wcwidth==0.1.9            # via pytest
diff --git a/tox.ini b/tox.ini
index 736b6e7..9b6d471 100644
--- a/tox.ini
+++ b/tox.ini
@@ -6,8 +6,7 @@
 skip_missing_interpreters = true
 
 [testenv]
-deps =
-    pytest
+deps = -r requirements/tests.txt
 commands = pytest --tb=short --basetemp={envtmpdir} {posargs}
 
 [testenv:style]
@@ -16,5 +15,5 @@
 commands = pre-commit run --all-files --show-diff-on-failure
 
 [testenv:docs]
-deps = -r docs/requirements.txt
+deps = -r requirements/docs.txt
 commands = sphinx-build -W -b html -d {envtmpdir}/doctrees docs {envtmpdir}/html