Skip to content
Snippets Groups Projects

Insert proper patch for py37+ support on dataclasses

Merged André Anjos requested to merge dataclasses-py37+ into master
3 files
+ 110
17
Compare changes
  • Side-by-side
  • Inline
Files
3
 
From 178831f257a0d7d1b112b77067890ba5fd44f9a4 Mon Sep 17 00:00:00 2001
 
From: Jon Dufresne <jon.dufresne@gmail.com>
 
Date: Thu, 3 Sep 2020 17:43:45 -0700
 
Subject: [PATCH] Allow installing on Python 3.7+ environments
 
 
On Python 3.7+ environments, use the builtin dataclasses module instead
 
of shadowing it. This is handled in the dataclasses/__init__.py which
 
sets the module in sys.modules.
 
 
This allows projects to pin dependencies that are then run in both
 
Python 3.6 and 3.7+ environments using tools such as pip-tools.
 
 
Previously, if dependencies were pinned for Python 3.6, the dataclasses
 
would be used, but fail to install on Python 3.7+ environments. On the
 
other hand, if dependencies were pinned for Python 3.7+, dataclasses
 
would not be available in Python 3.6 environments.
 
 
Projects typically pin dependencies using the oldest supported Python.
 
 
dataclasses has recently become a dependency of the popular tool Black,
 
which is how this issue was discovered.
 
 
Fixes #153
 
---
 
dataclasses/__init__.py | 17 +++++++++++++++++
 
dataclasses.py => dataclasses/dataclasses.py | 0
 
setup.py | 9 +++++++--
 
test/test_dataclasses.py | 11 +++++++++++
 
4 files changed, 35 insertions(+), 2 deletions(-)
 
create mode 100644 dataclasses/__init__.py
 
rename dataclasses.py => dataclasses/dataclasses.py (100%)
 
 
diff --git a/dataclasses/__init__.py b/dataclasses/__init__.py
 
new file mode 100644
 
index 0000000..7818f17
 
--- /dev/null
 
+++ b/dataclasses/__init__.py
 
@@ -0,0 +1,17 @@
 
+import importlib.util
 
+import os
 
+import sys
 
+
 
+for path in sys.path:
 
+ file_path = os.path.join(path, 'dataclasses.py')
 
+ if os.path.exists(file_path):
 
+ # Load the builtin module instead.
 
+ break
 
+else:
 
+ file_path = os.path.join(os.path.dirname(__file__), 'dataclasses.py')
 
+
 
+module_name = 'dataclasses'
 
+spec = importlib.util.spec_from_file_location(module_name, file_path)
 
+module = importlib.util.module_from_spec(spec)
 
+sys.modules[module_name] = module
 
+spec.loader.exec_module(module)
 
diff --git a/dataclasses.py b/dataclasses/dataclasses.py
 
similarity index 100%
 
rename from dataclasses.py
 
rename to dataclasses/dataclasses.py
 
diff --git a/setup.py b/setup.py
 
index e623a2a..84f1f68 100644
 
--- a/setup.py
 
+++ b/setup.py
 
@@ -17,8 +17,13 @@
 
"Intended Audience :: Developers",
 
"Topic :: Software Development :: Libraries :: Python Modules",
 
"License :: OSI Approved :: Apache Software License",
 
+ "Programming Language :: Python",
 
+ "Programming Language :: Python :: 3",
 
+ "Programming Language :: Python :: 3 :: Only",
 
"Programming Language :: Python :: 3.6",
 
+ "Programming Language :: Python :: 3.7",
 
+ "Programming Language :: Python :: 3.8",
 
],
 
- py_modules=["dataclasses"],
 
- python_requires=">=3.6, <3.7",
 
+ packages=["dataclasses"],
 
+ python_requires=">=3.6",
 
)
 
diff --git a/test/test_dataclasses.py b/test/test_dataclasses.py
 
index 741d0d6..5667f34 100644
 
--- a/test/test_dataclasses.py
 
+++ b/test/test_dataclasses.py
 
@@ -6,6 +6,8 @@
 
 
import pickle
 
import inspect
 
+import os
 
+import sys
 
import unittest
 
from unittest.mock import Mock
 
from typing import ClassVar, Any, List, Union, Tuple, Dict, Generic, TypeVar, Optional
 
@@ -3056,6 +3058,15 @@ def __post_init__(self, y):
 
 
## replace(c, x=5)
 
 
+ def test_import_shadows_builtin(self):
 
+ mod_path = dataclasses.__file__
 
+ self.assertTrue(mod_path.endswith('dataclasses.py'))
 
+ py36_suffix = os.path.join('dataclasses', 'dataclasses.py')
 
+ if sys.version_info < (3, 7):
 
+ self.assertTrue(mod_path.endswith(py36_suffix))
 
+ else:
 
+ self.assertFalse(mod_path.endswith(py36_suffix))
 
+
 
 
if __name__ == '__main__':
 
unittest.main()
Loading