-
Notifications
You must be signed in to change notification settings - Fork 101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Updated matplotlib hook to handle matplotlib.libs direcory (added in … #182
Conversation
…mpl >= 3.7.0 Added a hook for mpl_toolkits for the same reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this contribution! I just have a few minor change requests.
How about if add special functions to handle packages distributed by delvewheel? class TheFinderClass:
def add_dlls(self, path, suffixes=(".dll", ".pyd")):
path = os.path.realpath(path)
if os.path.isdir(path):
dlls = [os.path.join(path, fn)
for fn in os.listdir(path)
if fn.endswith(suffixes)]
for dll in dlls:
self.add_dll(dll)
def hook_delvewheel_dist(finder, module, need_ast=False):
"""Patches which distributed by delvewheel are not needed, here remove them
and move all the .dll files to the root of sys.executable.
If need_ast is False, module.__code_object__ will be replaced, return None.
If need_ast is True, return the AST object for post-use, don't forget
replace the code at the end.
"""
import ast
# we don't need ast.NodeTransformer to replace the whole subnode
class NodeVisitor(ast.NodeVisitor):
filter_assign = False
filter_constant = False
def visit_FunctionDef(self, node: ast.FunctionDef):
if not node.name.startswith("_delvewheel_init_patch_"):
return
try:
self.filter_assign = True
self.generic_visit(node)
except UserWarning:
pass
else:
import warnings
warnings.warn(f"{node.name} be matched, but no libs name be found",
RuntimeWarning, 3)
finally:
node.body = ast.parse("pass").body
# all done, early cancel
raise UserWarning
def visit_Assign(self, node: ast.Assign):
if not self.filter_assign:
return
target = node.targets[0]
if isinstance(target, ast.Name) and target.id == "libs_dir":
self.filter_constant = True
self.generic_visit(node)
self.filter_constant = False
def visit_Constant(self, node: ast.Constant):
self.add_dlls(node.value)
if hasattr(ast, "Str")
# py37 and below
def visit_Str(self, node: ast.Str):
self.add_dlls(node.s)
def add_dlls(self, name):
if self.filter_constant and isinstance(name, str):
finder.add_dlls(finder, os.path.join(
os.path.dirname(module.__file__), os.pardir, name))
# done, raise a signal
raise UserWarning
tree = ast.parse(module.__source__)
try:
NodeVisitor().visit(tree)
except UserWarning:
pass
if need_ast:
return tree
module.__code_object__ = compile(
tree, module.__file__, "exec", optimize=module.__optimize__) |
…ndle locale-data .dat files
Ultimately, I think @SeaHOH is onto a better solution, but I didn't know where to put/instanciate TheFinderClass so I left it out for now. |
It imply |
@SeaHOH Would you like to submit a PR with your solution? |
I tried to run this branch on Actions and now it fails on @SeaHOH Let me know if you want to prepare a PR, otherwise I can implement this feature based on the code that you provided up here and credit you in a comment. What is not entirely clear to me is how to hook this general purpose code in the specific hooks (e.g. |
I'd like to do, but actually will not, I have no time to test a lot of packages.
Yes, I think so, just a call, all works can be done in the function. |
…mpl >= 3.7.0
Added a hook for mpl_toolkits for the same reason.
Not sure if I handled mpl_toolkits < 3.7.0 properly (or if it needs to be handled for those versions)