pyflyby - Python开发生产工具,特别是自动导入管理
项目描述
Pyflyby 是一套适用于 Python 3.8+ 的 Python 编程生产力工具。
- 用于命令行交互
py:命令行多工具
- 用于 IPython 交互
autoimporter:在需要时自动导入符号。
- 用于编辑 Python 源代码
tidy-imports:添加缺失的‘导入’,删除未使用的‘导入’,并重新格式化导入块。
find-import:打印如何导入特定符号到 stdout。
reformat-imports:重新格式化 import 块
collect-imports:打印出给定文件集中所有的导入。
collect-exports:打印出给定模块集中的定义,形式为导入语句。
transform-imports:重命名导入的模块/函数。
安装
$ pip install pyflyby
- 这将在您的 ipython 中创建一个名为 py 的别名,该别名运行内部 pyflyby 插件。
pyflyby 依赖于 ipython,如果尚未安装,请使用以下命令进行安装
$ pip install ipython
快速入门:Autoimporter + IPython
$ py
In [1]: re.search("[a-z]+", "....hello...").group(0)
[PYFLYBY] import re
Out[1]: 'hello'
In [2]: chisqprob(arange(5), 2)
[PYFLYBY] from numpy import arange
[PYFLYBY] from scipy.stats import chisqprob
Out[2]: [ 1. 0.6065 0.3679 0.2231 0.1353]
要将 pyflyby 作为一次性加载到现有的 IPython 会话中
$ ipython
In [1]: %load_ext pyflyby
要配置 IPython/Jupyter Notebook 以自动加载 pyflyby
$ py pyflyby.install_in_ipython_config_file
或者
$ echo 'c.InteractiveShellApp.extensions.append("pyflyby")' \
>> ~/.ipython/profile_default/ipython_config.py
$ ipython
In [1]: b64decode('aGVsbG8=')
[PYFLYBY] from base64 import b64decode
Out[1]: 'hello'
自动导入延迟变量
可以使用自动导入器来延迟定义变量。
要使用,请将以下内容放入您的 IPython 启动文件(~/.ipython/profile_default/startup/autoimp.py)中,或者在您的 IPython 配置文件中
from pyflyby import add_import
add_import("foo", "foo = 1")
add_import(
"df, data as dd",
'''
import pandas as pd
data = [1,2,3]
df = pd.DataFrame(data)
''')
您可以将关键字 strict=False 添加到不失败,如果不在 IPython 中或 pyflyby 扩展没有加载。
快速入门:py 命令行多工具
$ py b64decode aGVsbG8=
[PYFLYBY] from base64 import b64decode
[PYFLYBY] b64decode('aGVsbG8=', altchars=None)
'hello'
$ py log2 sys.maxint
[PYFLYBY] from numpy import log2
[PYFLYBY] import sys
[PYFLYBY] log2(9223372036854775807)
63.0
$ py 'plot(cos(arange(30)))'
[PYFLYBY] from numpy import arange
[PYFLYBY] from numpy import cos
[PYFLYBY] from matplotlib.pyplot import plot
[PYFLYBY] plot(cos(arange(30)))
<plot>
$ py 38497631 / 13951446
2.7594007818257693
$ py foo.py
快速入门:tidy-imports
要使用 tidy-imports,只需指定要整理的文件名即可。
例如
$ echo 're.search("[a-z]+", "....hello..."), chisqprob(arange(5), 2)' > foo.py
$ tidy-imports foo.py
--- /tmp/foo.py
+++ /tmp/foo.py
@@ -1 +1,9 @@
+from __future__ import absolute_import, division, with_statement
+
+from numpy import arange
+from scipy.stats import chisqprob
+import re
+
re.search("[a-z]+", "....hello..."), chisqprob(arange(5), 2)
Replace /tmp/foo.py? [y/N]
快速入门:导入库
创建一个名为 .pyflyby 的文件,其中包含类似以下内容的行
from mypackage.mymodule import MyClass, my_function
import anotherpackage.anothermodule
您可以将此文件放在您的家目录中或与您的 *.py 文件相同的目录中。
详细信息:自动导入
自动导入 - 永远不再输入“导入”!
该模块允许您的“已知导入”在 IPython 交互会话中自动工作,无需输入导入语句(并且无需因偶尔使用的导入而减慢您的 Python 启动速度)。
示例
In [1]: re.search("[a-z]+", "....hello...").group(0) [PYFLYBY] import re Out[1]: 'hello' In [2]: chisqprob(arange(5), 2) [PYFLYBY] from numpy import arange [PYFLYBY] from scipy.stats import chisqprob Out[2]: [ 1. 0.6065 0.3679 0.2231 0.1353] In [3]: np.sin(arandom(5)) [PYFLYBY] from numpy.random import random as arandom [PYFLYBY] import numpy as np Out[3]: [ 0.0282 0.0603 0.4653 0.8371 0.3347] In [4]: isinstance(42, Number) [PYFLYBY] from numbers import Number Out[4]: True
它只需这样就可以工作
Tab 完成工作,即使在尚未导入的模块上也一样。在以下示例中,请注意,当我们需要了解其成员时,才会导入 numpy,并且仅在此之后
$ ipython In [1]: nump<TAB> In [1]: numpy In [1]: numpy.arang<TAB> [PYFLYBY] import numpy In [1]: numpy.arange
IPython的“?”魔法帮助(pinfo/pinfo2)在需要时将自动导入符号
$ ipython In [1]: arange? [PYFLYBY] from numpy import arange ... Docstring: arange([start,] stop[, step,], dtype=None) ...
其他IPython魔法命令也正常工作
$ ipython In [1]: %timeit np.cos(pi) [PYFLYBY] import numpy as np [PYFLYBY] from numpy import pi 100000 loops, best of 3: 2.51 us per loop $ echo 'print arange(4)' > foo.py $ ipython In [1]: %run foo.py [PYFLYBY] from numpy import arange [0 1 2 3]
实现细节
自动导入发生在解析时间,在代码执行之前。命名空间永远不会包含尚未导入的名称条目。
这种方法在解析时间导入与之前使用代理对象的自动导入实现形成对比。那些使用代理对象的实现效果不佳,因为无法使代理对象的行为完美。例如,如果x或T是代理对象,则instance(x, T)将返回错误答案。
兼容性
- 测试了以下版本
Python 3.8, 3.9, 3.10
IPython 0.10, 0.11, 0.12, 0.13, 1.0, 1.2, 2.0, 2.1, 2.2, 2.3, 2.4, 3.0, 3.1, 3.2, 4.0., 7.11(最新版)
IPython(文本控制台),IPython笔记本,Spyder
详情:导入库
Pyflyby使用“导入库”来指定如何导入给定的符号。
导入库文件只是一个包含‘import’(或‘from … import …’)行的Python源文件。这些可以使用 collect-imports 和 collect-exports 自动生成。
已知导入
find-imports,tidy-imports 和 autoimport 会查询已知导入的数据库以确定导入的位置。例如,如果导入数据库包含
from numpy import arange, NaN
那么当你在IPython中输入以下内容时
print(arange(10))
自动导入器将自动执行 from numpy import arange。
该数据库可以是一个文件或多个文件。这使得项目特定的 known_imports 能够与全局和用户默认值一起使用。
PYFLYBY_PATH 环境变量指定了要读取的文件。这是一个以冒号分隔的文件名或目录名列表。默认值为
PYFLYBY_PATH=/etc/pyflyby:~/.pyflyby:.../.pyflyby
如果你设置
PYFLYBY_PATH=/foo1/bar1:/foo2/bar2
则这会替换默认值。
您可以使用短横线来在路径中包含默认值。如果您设置
PYFLYBY_PATH=/foo1/bar1:-:/foo2/bar2
则这会读取 /foo1/bar1,然后是默认位置,然后是 /foo2/bar2。
在 $PYFLYBY_PATH 中,.../.pyflyby(用三个点表示)意味着将搜索所有祖先目录以查找名为“ .pyflyby”的成员。
例如,假设存在以下文件
/etc/pyflyby/stuff.py /u/quarl/.pyflyby/blah1.py /u/quarl/.pyflyby/more/blah2.py /proj/share/mypythonstuff/.pyflyby /proj/share/mypythonstuff/foo/bar/.pyflyby/baz.py /.pyflyby
进一步假设
/proj 是与 / 在不同文件系统上的。
$HOME=/u/quarl
那么默认情况下,tidy-imports /proj/share/mypythonstuff/foo/bar/quux/zot.py 将使用以下
/etc/pyflyby/stuff.py /u/quarl/.pyflyby/blah1.py /u/quarl/.pyflyby/more/blah2.py /proj/share/mypythonstuff/foo/bar/.pyflyby/baz.py /proj/share/mypythonstuff/.pyflyby (a file)
忘记导入
有时您可能需要让 pyflyby “忘记”已知导入数据库中的条目。
您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容
__forget_imports__ = ["from numpy import NaN"]
这很有用,如果你想要使用一组由其他人维护的导入,除了几个特定的导入。
$PYFLYBY_PATH 中的条目将按照指定的顺序从左到右处理,因此请将包含这些文件的目录放在你的 $PYFLYBY_PATH 的末尾。默认情况下,tidy-imports 和其他工具会处理 /etc/pyflyby,然后是 ~/.pyflyby,最后是每个目录下的 .pyflyby。
强制导入
在某个项目中,你可能有一个策略,始终包含某些导入。例如,你可能希望在所有文件中都执行 from __future__ import division。
您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容
__mandatory_imports__ = ["from __future__ import division"]
要撤销从其他 .pyflyby 文件继承的强制导入,请使用 __forget_imports__(见上文)。
标准化导入
有时你希望每次运行 tidy-imports 时都自动将导入重命名为新名称。
您可以在 $PYFLYBY_PATH 可达的任何文件中放置以下内容
__canonical_imports__ = {"oldmodule.oldfunction": "newmodule.newfunction"}
这相当于运行
tidy-imports --transform=oldmodule.oldfunction=newmodule.newfunction
肥皂箱:避免使用“星号”导入
在 Python 中编程时,避免在生产代码中使用 from foopackage import * 是一种良好的软件工程实践。
这种风格是维护噩梦
很难弄清楚各种符号(函数、类等)来自哪里。
很难判断什么被什么覆盖了。
当包以微不足道的方式发生变化时,你的代码将受到影响。考虑以下示例:假设 foopackage.py 包含 import sys,而 myprogram.py 包含 from foopackage import *; if some_condition: sys.exit(0)。如果 foopackage.py 中的 import sys 被删除,则 myprogram.py 现在已损坏,因为它缺少 import sys。
要修复此类代码,你可以运行 tidy-imports --replace-star-imports 以自动将星号导入替换为特定需要的导入。
tidy-imports 的项目配置
你可以通过使用 pyproject.toml 文件的 [tool.pyflyby] 部分来基于存储库配置 Pyflyby。Pyflyby 将在当前工作目录及其所有父目录中查找,直到找到 pyproject.toml 文件,然后从中加载默认值。
大多数长命令行标志的默认值都可以在这个部分中配置。只需使用长选项名称,用下划线 _ 替换破折号 -。对于形式为 –xxx 和 –no-xxx 的长选项,你可以将布尔值分配给 xxx。例如
[tool.pyflyby] add_missing=true from_spaces=7 remove_unused=false
Emacs 支持
要在 GNU Emacs 中获取 M-x tidy-imports 命令,请将其添加到你的 ~/.emacs 中。
(load "/path/to/pyflyby/lib/emacs/pyflyby.el")
Pyflyby.el 还不支持 XEmacs;欢迎提供补丁。
许可证
Pyflyby 在非常宽松的许可下发布,即 MIT/X11 许可证;请参阅 LICENSE.txt。
发布
在 lib/python/pyflyby/_version.py 中检查版本号,可能需要增加它。
如有必要,进行提交和标记,然后推送标签/提交。
可选:设置 SOURCE_DATE_EPOCH 以实现可重复构建
export SOURCE_DATE_EPOCH=$(git show -s --format=%ct HEAD)
构建 SDIST
python setup.py sdist
可选:使用 IPython 工具重新打包 SDIST 以确保 ZIP 只包含 SOURCE_DATE_EPOCH 日期
python ~/dev/ipython/tools/retar.py dist/pyflyby-1.7.8.tar.gz shasum -a 256 dist/*
可选,重复 4 & 5 以验证校验和未更改。
使用 twine 上传
twine upload dist/*
检查/更新 https://github.com/conda-forge/pyflyby-feedstock 以获取 conda-forge 上的新 pyflyby 版本
项目详情
pyflyby-1.9.6.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 479c5b10c7e1d1e3fe840a9a8bbff46da93f289a11a8c0f0ff1066040fdacc41 |
|
MD5 | 14ff8cc55b795e6f31d28945c7f07d3c |
|
BLAKE2b-256 | 0cb9a5e6be18c9bed0e6353ee405881742bba8d397af93158619571acd052d9b |