1
- from functools import partial
2
- import inspect
3
- import re
4
1
from pathlib import Path
2
+ import tokenize
5
3
6
4
import setuptools
7
- from setuptools import Extension , find_packages
5
+ from setuptools import Distribution , Extension , find_packages
8
6
from setuptools .command .build_ext import build_ext
9
- from setuptools .command .develop import develop
10
- from setuptools .command .install_lib import install_lib
11
7
12
8
13
9
__all__ = ["Extension" , "build_ext" , "find_packages" , "setup" ]
@@ -22,49 +18,43 @@ def build_extensions(self):
22
18
super ().build_extensions ()
23
19
24
20
25
- class setup :
26
- _pth_hooks = {}
27
-
28
- def __new__ (cls , ** kwargs ):
29
-
30
- cmdclass = kwargs .setdefault ("cmdclass" , {})
31
-
32
- class pth_hook_mixin :
33
-
34
- def run (self ):
35
- super ().run ()
36
- for fname , (name , source ) in cls ._pth_hooks .items ():
37
- with Path (self .install_dir , fname ).open ("w" ) as file :
38
- file .write (f"import os; exec({ source !r} ); { name } ()" )
39
-
40
- def get_outputs (self ):
41
- return (super ().get_outputs ()
42
- + [str (Path (self .install_dir , fname ))
43
- for fname in cls ._pth_hooks ])
44
-
45
- cmdclass ["develop" ] = type (
46
- "develop_with_pth_hook" ,
47
- (pth_hook_mixin , cmdclass .get ("develop" , develop )),
48
- {})
49
- cmdclass ["install_lib" ] = type (
50
- "install_lib_with_pth_hook" ,
51
- (pth_hook_mixin , cmdclass .get ("install_lib" , install_lib )),
52
- {})
53
-
54
- setuptools .setup (** kwargs )
55
-
56
- @classmethod
57
- def register_pth_hook (cls , fname , func = None ):
58
- if func is None :
59
- return partial (cls .register_pth_hook , fname )
60
- source = inspect .getsource (func )
61
- if not re .match (r"\A@setup\.register_pth_hook.*\ndef " , source ):
62
- raise SyntaxError ("register_pth_hook must be used as a toplevel "
63
- "decorator to a function" )
64
- _ , source = source .split ("\n " , 1 )
65
- d = {}
66
- exec (source , {}, d )
67
- if set (d ) != {func .__name__ }:
68
- raise SyntaxError (
69
- "register_pth_hook should define a single function" )
70
- cls ._pth_hooks [fname ] = func .__name__ , source
21
+ def register_pth_hook (source_path , pth_name ):
22
+ """
23
+ ::
24
+ setup.register_pth_hook("hook_source.py", "hook_name.pth") # Add hook.
25
+ """
26
+ with tokenize .open (source_path ) as file :
27
+ source = file .read ()
28
+ _pth_hook_mixin ._pth_hooks .append ((pth_name , source ))
29
+
30
+
31
+ class _pth_hook_mixin :
32
+ _pth_hooks = []
33
+
34
+ def run (self ):
35
+ super ().run ()
36
+ for pth_name , source in self ._pth_hooks :
37
+ with Path (self .install_dir , pth_name ).open ("w" ) as file :
38
+ file .write (f"import os; exec({ source !r} )" )
39
+
40
+ def get_outputs (self ):
41
+ return (super ().get_outputs ()
42
+ + [str (Path (self .install_dir , pth_name ))
43
+ for pth_name , _ in self ._pth_hooks ])
44
+
45
+
46
+ def _prepare_pth_hook (kwargs ):
47
+ cmdclass = kwargs .setdefault ("cmdclass" , {})
48
+ get = Distribution ({"cmdclass" : cmdclass }).get_command_class
49
+ cmdclass ["develop" ] = type (
50
+ "develop_with_pth_hook" , (_pth_hook_mixin , get ("develop" )), {})
51
+ cmdclass ["install_lib" ] = type (
52
+ "install_lib_with_pth_hook" , (_pth_hook_mixin , get ("install_lib" )), {})
53
+
54
+
55
+ def setup (** kwargs ):
56
+ _prepare_pth_hook (kwargs )
57
+ setuptools .setup (** kwargs )
58
+
59
+
60
+ setup .register_pth_hook = register_pth_hook
0 commit comments