Repository: scrapy/scrapy

Issue:
Make Python 3.8 support official
This involves, among other things:
- Enabling a Python 3.8 environment in Tox
- Enabling a Python 3.8 job in the Travis CI
- Updating the `setup.py` file


Discussion:
Does Travis already support it?
According to https://docs.travis-ci.com/user/languages/python/ it does
I am trying to install scrapy for python 3.8 in a Windows environment. Are there currently any ways I can do this? Or is this blocked upstream by conda https://github.com/conda/conda/issues/9343
> I am trying to install scrapy for python 3.8 in a Windows environment. Are there currently any ways I can do this? Or is this blocked upstream by conda [conda/conda#9343](https://github.com/conda/conda/issues/9343)

You can try using `pip`. If you cannot get it to work with `pip`, then you’ll need to wait for Conda to support Python 3.8.
Hey! I'll grab this one if it is okay?
> > I am trying to install scrapy for python 3.8 in a Windows environment. Are there currently any ways I can do this? Or is this blocked upstream by conda [conda/conda#9343](https://github.com/conda/conda/issues/9343)
> 
> You can try using `pip`. If you cannot get it to work with `pip`, then you’ll need to wait for Conda to support Python 3.8.

No luck using just `pip install scrapy` unfortunately.

Resolving patch:
diff --git a/scrapy/extensions/httpcache.py b/scrapy/extensions/httpcache.py
--- a/scrapy/extensions/httpcache.py
+++ b/scrapy/extensions/httpcache.py
@@ -1,19 +1,24 @@
 from __future__ import print_function
-import os
+
 import gzip
 import logging
-from six.moves import cPickle as pickle
+import os
+from email.utils import mktime_tz, parsedate_tz
 from importlib import import_module
 from time import time
+from warnings import warn
 from weakref import WeakKeyDictionary
-from email.utils import mktime_tz, parsedate_tz
+
+from six.moves import cPickle as pickle
 from w3lib.http import headers_raw_to_dict, headers_dict_to_raw
+
+from scrapy.exceptions import ScrapyDeprecationWarning
 from scrapy.http import Headers, Response
 from scrapy.responsetypes import responsetypes
-from scrapy.utils.request import request_fingerprint
-from scrapy.utils.project import data_path
 from scrapy.utils.httpobj import urlparse_cached
+from scrapy.utils.project import data_path
 from scrapy.utils.python import to_bytes, to_unicode, garbage_collect
+from scrapy.utils.request import request_fingerprint
 
 
 logger = logging.getLogger(__name__)
@@ -345,6 +350,8 @@ def _read_meta(self, spider, request):
 class LeveldbCacheStorage(object):
 
     def __init__(self, settings):
+        warn("The LevelDB storage backend is deprecated.",
+             ScrapyDeprecationWarning, stacklevel=2)
         import leveldb
         self._leveldb = leveldb
         self.cachedir = data_path(settings['HTTPCACHE_DIR'], createdir=True)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -56,6 +56,7 @@ def has_environment_marker_platform_impl_support():
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
         'Programming Language :: Python :: 3.7',
+        'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
         'Topic :: Internet :: WWW/HTTP',


Test patch:
diff --git a/tests/test_downloadermiddleware_httpcache.py b/tests/test_downloadermiddleware_httpcache.py
--- a/tests/test_downloadermiddleware_httpcache.py
+++ b/tests/test_downloadermiddleware_httpcache.py
@@ -6,6 +6,7 @@
 import email.utils
 from contextlib import contextmanager
 import pytest
+import sys
 
 from scrapy.http import Response, HtmlResponse, Request
 from scrapy.spiders import Spider
@@ -154,9 +155,13 @@ def _get_settings(self, **new_settings):
         new_settings.setdefault('HTTPCACHE_GZIP', True)
         return super(FilesystemStorageTest, self)._get_settings(**new_settings)
 
+
 class LeveldbStorageTest(DefaultStorageTest):
 
-    pytest.importorskip('leveldb')
+    try:
+        pytest.importorskip('leveldb')
+    except SystemError:
+        pytestmark = pytest.mark.skip("Test module skipped - 'SystemError: bad call flags' occurs when >= Python 3.8")
     storage_class = 'scrapy.extensions.httpcache.LeveldbCacheStorage'