python 源分发 (sdist) - 生成的数据文件
python source distribution (sdist) - generated data files
在构建我的包期间,我正在生成 个数据文件。
我想创建源分发 (setup.py sdist),比如如果它们最初在源树中,但是,我不想在源代码树中生成它们,但在其他地方(最好是 build/generated),以免弄乱我的源代码(并意外提交)。
比如最后我想在[=25=下有data.txt ]dist_root/generated/data.txt
("dist_root" 是 setup.py 所在的位置)。
我使用了 data_files setuptools(不是 package_data 因为这个数据不是包的)并遇到了以下问题:
- 如果我在构建下生成 data.txt,它会被删除,因为进程正在过滤 build_base 下的任何文件。
- 如果我在某个临时文件夹下生成它,比如 dist_root/temp/data.txt,这个 "temp" 文件夹被链接。
所以如果我把 data_files = [('generated, temp/data.txt)], 我会得到一个链路径
dist_root/生成/temp/data.txt
看来我唯一的选择就是在dist_root/generated/data.txt下生成它
但是,又一次,我弄乱了我的源代码树,不知道如何清理它,因为这个 "generated" 文件夹名称是动态的。
有什么解决方法吗?
首选解决方案:将文件写入源目录,sdist
完成后删除它们
您可以覆盖 sdist
命令以在源目录中写入文件并在命令完成后清理它们:
import os
from distutils import dir_util
from setuptools import setup
from setuptools.command.sdist import sdist as sdist_orig
class sdist(sdist_orig):
def run(self):
# generate data files
genbase = os.path.join(os.path.dirname(__file__), 'temp')
self.mkpath(genbase)
with open(os.path.join(genbase, 'data.txt'), 'w') as fp:
fp.write('hello distutils world')
# run original sdist
super().run()
# clean up generated data files
dir_util.remove_tree(genbase, dry_run=self.dry_run)
setup(
...
data_files=[
('generated', ['temp/data.txt']),
],
cmdclass={'sdist': sdist},
)
生成数据文件而不将它们写入源目录
正在 sdist
temp
中调整源元数据
虽然很脏,但最简单的方法是直接在 sdist 目录中更新源元数据。这样,您仍将拥有有效的 egg 元数据,并且不必在整个 sdist
方式中处理丢失的源文件。
genfiles = ['temp/data.txt']
class sdist(sdist_orig):
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
for path in genfiles:
fullpath = os.path.join(base_dir, path)
self.mkpath(os.path.dirname(fullpath))
if not self.dry_run:
with open(fullpath, 'w') as fp:
fp.write('hello distutils world')
# also adapt source metadata file
cmd_egg_info = self.get_finalized_command('egg_info')
sourcemeta = os.path.join(base_dir,
cmd_egg_info.egg_name + '.egg-info',
'SOURCES.txt')
with open(sourcemeta, 'a') as fp:
fp.write('\n')
fp.write(path)
setup(
...,
data_files=[
('generated', genfiles),
],
cmdclass={'sdist': sdist},
)
基本上,在实际复制源文件之前,生成的数据文件会被忽略。然后,生成文件(作为复制现有文件的替代),并且由于源元数据不完整,因此使用生成的文件对其进行更新。
在元数据中写入不存在的文件
我强烈建议不要这样做。
所有其他方法会更脏,因为它们会将不存在的文件写入元数据并使 distutils
/setuptools
在整个生成过程中忽略不存在的文件源分布。但如果你坚持,这里有一个尽可能少的 monkeypatching 的解决方案:
genfiles = ['temp/data.txt']
class FileList(setuptools.command.egg_info.FileList):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.files += genfiles
def _safe_path(self, path):
return path in genfiles or super()._safe_path(path)
class sdist(sdist_orig):
def run(self):
# monkeypatch begin
FileListOrig = setuptools.command.egg_info.FileList
setuptools.command.egg_info.FileList = FileList
# monkeypatch end
super().run()
# restore the original class
setuptools.command.egg_info.FileList = FileListOrig
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
for path in genfiles:
fullpath = os.path.join(base_dir, path)
self.mkpath(os.path.dirname(fullpath))
if not self.dry_run:
with open(fullpath, 'w') as fp:
fp.write('hello distutils world')
setup(
...,
data_files=[
('generated', genfiles),
],
cmdclass={'sdist': sdist},
)
在构建我的包期间,我正在生成 个数据文件。
我想创建源分发 (setup.py sdist),比如如果它们最初在源树中,但是,我不想在源代码树中生成它们,但在其他地方(最好是 build/generated),以免弄乱我的源代码(并意外提交)。
比如最后我想在[=25=下有data.txt ]dist_root/generated/data.txt ("dist_root" 是 setup.py 所在的位置)。
我使用了 data_files setuptools(不是 package_data 因为这个数据不是包的)并遇到了以下问题:
- 如果我在构建下生成 data.txt,它会被删除,因为进程正在过滤 build_base 下的任何文件。
- 如果我在某个临时文件夹下生成它,比如 dist_root/temp/data.txt,这个 "temp" 文件夹被链接。
所以如果我把 data_files = [('generated, temp/data.txt)], 我会得到一个链路径 dist_root/生成/temp/data.txt
看来我唯一的选择就是在dist_root/generated/data.txt下生成它 但是,又一次,我弄乱了我的源代码树,不知道如何清理它,因为这个 "generated" 文件夹名称是动态的。
有什么解决方法吗?
首选解决方案:将文件写入源目录,sdist
完成后删除它们
您可以覆盖 sdist
命令以在源目录中写入文件并在命令完成后清理它们:
import os
from distutils import dir_util
from setuptools import setup
from setuptools.command.sdist import sdist as sdist_orig
class sdist(sdist_orig):
def run(self):
# generate data files
genbase = os.path.join(os.path.dirname(__file__), 'temp')
self.mkpath(genbase)
with open(os.path.join(genbase, 'data.txt'), 'w') as fp:
fp.write('hello distutils world')
# run original sdist
super().run()
# clean up generated data files
dir_util.remove_tree(genbase, dry_run=self.dry_run)
setup(
...
data_files=[
('generated', ['temp/data.txt']),
],
cmdclass={'sdist': sdist},
)
生成数据文件而不将它们写入源目录
正在 sdist
temp
中调整源元数据
虽然很脏,但最简单的方法是直接在 sdist 目录中更新源元数据。这样,您仍将拥有有效的 egg 元数据,并且不必在整个 sdist
方式中处理丢失的源文件。
genfiles = ['temp/data.txt']
class sdist(sdist_orig):
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
for path in genfiles:
fullpath = os.path.join(base_dir, path)
self.mkpath(os.path.dirname(fullpath))
if not self.dry_run:
with open(fullpath, 'w') as fp:
fp.write('hello distutils world')
# also adapt source metadata file
cmd_egg_info = self.get_finalized_command('egg_info')
sourcemeta = os.path.join(base_dir,
cmd_egg_info.egg_name + '.egg-info',
'SOURCES.txt')
with open(sourcemeta, 'a') as fp:
fp.write('\n')
fp.write(path)
setup(
...,
data_files=[
('generated', genfiles),
],
cmdclass={'sdist': sdist},
)
基本上,在实际复制源文件之前,生成的数据文件会被忽略。然后,生成文件(作为复制现有文件的替代),并且由于源元数据不完整,因此使用生成的文件对其进行更新。
在元数据中写入不存在的文件
我强烈建议不要这样做。
所有其他方法会更脏,因为它们会将不存在的文件写入元数据并使 distutils
/setuptools
在整个生成过程中忽略不存在的文件源分布。但如果你坚持,这里有一个尽可能少的 monkeypatching 的解决方案:
genfiles = ['temp/data.txt']
class FileList(setuptools.command.egg_info.FileList):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.files += genfiles
def _safe_path(self, path):
return path in genfiles or super()._safe_path(path)
class sdist(sdist_orig):
def run(self):
# monkeypatch begin
FileListOrig = setuptools.command.egg_info.FileList
setuptools.command.egg_info.FileList = FileList
# monkeypatch end
super().run()
# restore the original class
setuptools.command.egg_info.FileList = FileListOrig
def make_release_tree(self, base_dir, files):
super().make_release_tree(base_dir, files)
for path in genfiles:
fullpath = os.path.join(base_dir, path)
self.mkpath(os.path.dirname(fullpath))
if not self.dry_run:
with open(fullpath, 'w') as fp:
fp.write('hello distutils world')
setup(
...,
data_files=[
('generated', genfiles),
],
cmdclass={'sdist': sdist},
)