Archive for python

最近又在写ansible相关的东西,因为得集成python项目,我开始都想之间命令方式调用ansible了。因为之前搞了好几个版本的ansible集成,每次都是大折腾一段时间,而且最早的时候,因为要集成或者解决问题,需要查看ansible源码,发现就是一坨。我好像不止一次跟别的同事说ansible是看过的最垃圾的开源代码。 最近又开始折腾了,虽然封装的接口还是不好用,但是看源码和修改给的example,最起码折腾起来轻松一点点了。源码也写的比之前好太多了。 playbook这玩意更坑,可能也是我写的不太多。

Continue

最近接入他们大学的课题程序,很多都是用matplotlib画图,展示最终的精确度之类的。 然后我用pyenv+virtualenv安装那些程序的依赖,然后matplotlib需要_tkinter,这个还需要系统安装,虽然能装,但是挺费劲,还有种方式可能需要重新编译python,也是麻烦。网上搜索发现可以不使用的方法,每次装一次找一次,决定记录一下了。 直接import matplotlib.pyplot as plt 会报错ImportError: No module named _tkinter, please install the python-tk package 一般都是用plt.show()方式直接展示。我给改成plt.savefig()报错图片了。 网上找到的方法 在import之前加入两行:import matplotlib matplotlib.use('agg') 然后就可以了。好像是选了matplotlib里gui别的显示方式,就不依赖_tkinter了

Continue

代码基本网上搜的,没啥贴的,写一下思路,有需要的自己网上搜就行了。主要是自己看的电子书是扫描版的pdf,里边全是图片,超级大,好几百M。之前找了一圈,靠谱软件需要收费,不靠谱个人软件只能windwos下用。于是自己搞吧,发现也不太难。 第一步是把pdf提取图片 用到pymupdf库,这个是封装的c的接口,感觉写个pdf软件也不难啊,都有开源库,不知道为啥他们还收费。我提取图片发现,好多水印图片是直接用pdf编辑软件加上的,导致水印可以直接从提取的图片里边删掉,这个挺好。 第二步,把图片二值化 这里用到opencv,用到cv2.threshold。这个阈值不太好设置,可以使用cv2.THRESH_OTSU,提取一个分析值,但是这个不是最优的,有的书是半彩页的,书边会有浅色的背景之类,或者重点颜色等。这个有分析建议值之后,还需要自己试一下哪个值比较好。 第三部,把图片生成新pdf 这个还是用pymupdf库,基本都差不多。 没想到的是压缩率还挺低,一百多MB的pdf能压缩成十多兆。可能也是之前的pdf质量比较高吧。但是我看了一下压缩后的,清晰度一点不减少。有背景色的地方,选择阈值合适,背景色也都过滤掉了,文字不受影响。

Continue

主要看pymain_run_filename,是文件执行pymain_open_filename,不是文件赋值fp = stdin,最后执行pymain_run_file(fp, pymain->filename, cf)。看这里应该交互和文件执行都在这一个里边的。 pymain_open_filename就是打开文件返回句柄。 pymain_run_file文件里,主要就是调用PyRun_AnyFileExFlags。下面应该与main.c没关系了,主要在Python/pythonrun.c里了. pymain_repl里调用 PyRun_AnyFileFlags,然后也是调用的PyRun_AnyFileExFlags。 PyRun_AnyFileExFlags里, Py_FdIsInteractive判断是否是交互模式,如果是调用PyRun_InteractiveLoopFlags,里边有个do,这个不看了。如果不是调用PyRun_SimpleFileExFlags, 先调用PyImport_AddModule,interp->modules里插入了__main__,对我没啥用。maybe_pyc_file判断是否是pyc文件,比较了文件后缀,MagicNumber. MAGIC_NUMBER是在Lib/importlib的_bootstrap_external.py文件里定义的,直接写在python文件里了。 如果像pyc文件,关闭文件句柄,重新打开文件,然后调用set_main_loader,再调用run_pyc_file。 如果不像pyc文件,调用PyRun_FileExFlags。 set_main_loader中通过loader_name,从importlib/_bootstrap_external中获取loader,源码为SourceFileLoader,pyc为SourcelessFileLoader,设置到__loader__ run_pyc_file,先比较MagicNumber是否匹配,然后PyMarshal_ReadLastObjectFromFile读取文件,其中的就不看了,不关心。PyEval_EvalCode应该是执行代码了,这个也不看了。 然后就完结了。 import 相关 第一篇里边的pymain_init_sys_path,调用pymain_get_importer,然后调用PyImport_GetImporter,然后调用get_path_importer,然后从path_hooks里找合适的import的方法进行导入 pymain_update_sys_path更新sys.path config_init_module_search_paths里有个Py_GetPath(,这里比较乱,调用了几次_PyPathConfig_Init,我也没仔细看。_PyPathConfig_Calculate里应该是初始化的path,没仔细看。 第三方库的搜索路径添加在initsite,导入Lib/site.py模块,执行addusersitepackages里添加的

Continue

按照上一篇的流程 Modules/main.c里, pymain_main里pymain_init里的pymain_cmdline,是解析参数的。 初始化一个_PyCmdline,暂存参数的 line464 typedef struct { wchar_t **argv; int nwarnoption; /* Number of -W options */ wchar_t **warnoptions; /* -W options */ int nenv_warnoption; /* Number of PYTHONWARNINGS options */ wchar_t **env_warnoptions; /* PYTHONWARNINGS options */ int print_help; /* -h, -? options */ int print_version; /* -V option */ int bytes_warning; /* Py_BytesWarningFlag, -b */ int debug; /* Py_DebugFlag, -b, PYTHONDEBUG */ int inspect; /* Py_InspectFlag, -i, PYTHONINSPECT */ int interactive; /* Py_InteractiveFlag, -i */ int isolated; /* Py_IsolatedFlag, -I */ int optimization_level; /* Py_OptimizeFlag, -O, PYTHONOPTIMIZE */ int dont_write_bytecode; /* Py_DontWriteBytecodeFlag, -B, PYTHONDONTWRITEBYTECODE */ int no_user_site_directory; /* Py_NoUserSiteDirectory, -I, -s, PYTHONNOUSERSITE */ int no_site_import; /* Py_NoSiteFlag, -S */ int use_unbuffered_io; /* Py_UnbufferedStdioFlag, -u, PYTHONUNBUFFERED */ int verbosity; /* Py_VerboseFlag, -v, PYTHONVERBOSE */ int quiet_flag; /* Py_QuietFlag, -q */ const char *check_hash_pycs_mode; /* --check-hash-based-pycs */ #ifdef MS_WINDOWS int legacy_windows_fs_encoding; /* Py_LegacyWindowsFSEncodingFlag, PYTHONLEGACYWINDOWSFSENCODING */ int legacy_windows_stdio; /* Py_LegacyWindowsStdioFlag, PYTHONLEGACYWINDOWSSTDIO */ #endif } _PyCmdline; 然后调用cmdline_get_global_config,设置默认参数,默认参数都在 Python/pylifecycle.c 全为0.后面的cmdline_set_global_config是设置全局值的。两个是一对 然后调用pymain_cmdline_impl,里面调用pymain_read_conf,看了一下,主要在函数pymain_parse_cmdline_impl里面。其他的就不看了。 cmdline_get_env_flags是从环境拿值设置参数的。 pymain_init_core_argv是设置-c-m俩参数 没想到比较简单,没有细看,看的这些基本能达到目的了。有需要再补充

Continue

看Makefile.pre.in文件,入口函数在Programs/python.c文件里,发现main函数。 只调用的Modules/main.c的_Py_UnixMain函数,这里面初始化了_PyMain,用来保存参数,然后调用pymain_main 先调用pymain_init,后调用pymain_run_python,最后调用pymain_free. pymain_init里,初始化_PyCoreConfig,大体看是pyvm的一些参数,先不关心。然后调用pymain_cmdline,大体看是解析参数的,不关心。pymain_init_stdio设置了stdin_is_interactive的值,这个可能有用,先记录。然后调用_Py_InitializeCore,里边调用_Py_InitializeCore_impl,里边各种初始化,不跟进去看了。 里边调用了一个_PyImport_Init,没啥,_PyImportHooks_Init,初始化了几个sys的参数,但是都是空值, sys.meta_path, sys.path_importer_cache,sys.path_hooks,这几个有用。 _Py_InitializeCore_impl最后调用了一个initimport(, sys.modules不知道在哪初始化的,可能有用,先不找了。importlib的导入,然后是_PyImportZip_Init. _PyImportZip_Init在Python/import.c里,导入zipimport,path_hooks里加入了一个zipimport.zipimporter。搞定 回到 pymain_init, 最后调用了 pymain_init_python_main 和pymain_init_sys_path. pymain_init_python_main调用_Py_InitializeMainInterpreter好像仅仅是重新设置了一下参数,这里没看懂,从自己复制了参数设置了args,有设置了一遍。没啥用先不管了。 pymain_init_sys_path这个看名字是要找的了, 第一个是zip或者目录导入,这个有用,记录一下,暂时不会用。从参数中获取sys.path的配置,最后调用pymain_update_sys_path插入到sys.path里边 pymain_run_python中,先调用pymain_header,pymain_import_readline,pymain_run_command,pymain_run_module, pymain_run_filename, pymain_repl. pymain_header,如果是交互模式,打印了版本和操作系统。可以查到版本信息在Include/patchlevel.h pymain_import_readline 为交互模式导入readline模块。pymain_run_command,直接执行的代码。pymain_run_module执行模块的. pymain_run_filename 执行文件的。 pymain_repl 解析器模式 这部分就基本看完了,下边要单独看一下,启动参数解析的地方

Continue

先写解决方案:制定dasconfig的failoverLevel = 1,就解决了。 这是一个必传的参数。但是官网特别说明,所有参数都是可选的。All fields are optional. 然后报错“指定的参数不正确:”也没写哪个参数不正确。 我是google搜索找到了解决方案,而且还是六七年前的帖子,也就是说这个问题持续六七年了吗??? vmware文档啥分类没有,我找都是从manager到数据方法,或者dir看到了,直接搜索。太麻烦了。而且返回的数据是关联返回的,虽然可以制定返回的字段。

Continue

折腾了我一个周五下午加一个周末的问题。 写的代码上线两个周了,之前只测试了同步跟列表的功能,展示没问题,上周测试了一下更新问题,开始删除没刷新,我还以为是前端老版本的编译有问题,发现接口确实调用了就没管了。 直到测试一个更新功能,发现接口调用成功了,但是数据没更新。还返回了http 200。我就看了一下代码,返回200不可能没执行到更新保存的代码。 发现只有在提交commit之前有查询操作,就会导致表更新失败。所以应该是个session问题。 试了我本机环境没问题,然后我就想到装的python包的版本问题,踩什么bug了吧。然后我对比了一下版本,我管理都是只写主要包的版本,依赖包的版本没有写,所以依赖包有的版本会高一点。 我选了几个可能的包,更换版本,发现不是这个原因。周末想想,如果是这个包的问题,应该早就发现了,会打补丁。 然后我就想到数据库的问题,我用的mariadb,测试系统是centos,然后我看了一下有新版本的mariadb,更新了一下,这里现在想想数据库的问题的概率也十分小了,而且是这么明显的bug。 mariadb的源巨慢无比,我又在尝试更新mysqlclient包,因为我记得安装的时候mariadb-devel不能用,网上说的用mysql-devel。我又从新试了一次,各种方法,发现不成功。 到下午快下班,安装完mariadb,又试了一遍mariadb-devel也不行。觉得还是用mysql,又安装称mysql。 但是发现数据库数据文件不兼容,升级的命令好像也不太行,我备份的导出数据库数据,导入又有外键关联的限制,懒得搞数据了。下班了。 周末有时间的时候就想了想,我之前虽然抓包测试环境mysql,发现没问题,但是没对比本机的。如果周一mysql不行,试试本机环境连线上数据库,排除一下是包的问题还是数据库问题。感觉周五的时候应该先排除问题再更新数据库才对。 周一来,同步了一下数据,更新了一下发现mysql还是不行。然后重新编译mysqlclient,测试发现通过了。 最后还是mysqlclient编译依赖有问题,使用mysql-devel编译,连接mariadb有问题。好像还不是所有的版本有这个问题。

Continue

做个项目要解析mysql sql语句,使用开源的库发现问题很多,不太适合。推荐的几个项目都是项目里边集成的,语言也不符合,太麻烦。只能自己搞了,选择antlr的原因是官方提供mysql解析的语法,做起来比较简单。   安装: curl -O http://www.antlr.org/download/antlr-4.5.3-complete.jar 然后写一个shell脚本antlr,用来执行命令 #!/bin/bash java -cp .:./antlr-4.5.3-complete.jar:$CLASSPATH org.antlr.v4.Tool $* 从https://github.com/antlr/grammars-v4.git clone一些已经写好的sql语法文件。   生成Python版的解析代码。 ./antlr  -Dlanguage=Python2  MySQLLexer.g4 ./antlr  -Dlanguage=Python2 -visitor  MySQLParser.g4 第二个加参数是为了生成MySQLGrammarVisitor。   然后参照例子写了个函数包起来就能用。这工具做的好,原因就是不用研究太深就能用。

Continue

想研究一下virtualenv是怎样保证python运行环境独立的。库里边带了几个二进制,导致clone源代码的时候发现库好大啊,当时就祈祷源码不要太多。 目录结构 大体看了一下文件目录,主要文件就一个virtualenv.py。(也确实安装完就这一个文件) bin/rebuild-script.py这个文件是用来构建新的virtualenv.py文件的。 virtualenv_embedded 文件夹里边的文件是 生成虚拟环境后的脚本,但不是最终版的。上边构建文件将这几个文件插入virtualenv.py virtualenv_support 几个二进制库 创建一个环境 $ virtualenv ENV 从virtualevn main()入手,2000多行。前边解析参数,extend_parser和adjust_options可以自定义修改参数,目的应该是可以使创建环境的命令简单。after_install是环境创建完成后执行,可以做一些基础包的安装等操作。我猜virtualenvwrapper应该会对这几个函数定义。 --python参数可以指定解析器的版本。resolve_interpreter是返回指定解析器的绝对路径,作者使用path变量和提供的执行文件名组合再判断文件是否存在,是否可执行来判断。我感觉可以直接使用which取一下,差不多。 VIRTUALENV_INTERPRETER_RUNNING是判断是否使用的指定解析器,不是指定解析器,就更改变量,用指定解析器重新执行。是的话就继续执行。在加载文件的时候判断是指定解析器,把virtualenv安装环境的path去掉。 后面删掉了PYTHONHOME,make_environment_relocatable好像是对环境目录移动复制等操作后进行重定向,这个没用过。主要就把环境bin目录下的文件的python执行解析器,修改lib库文件路径 create_environment就是创建环境的函数了,第一个参数是环境根目录,后边都是执行参数。 path_locations 根据不同系统解析器环境,返回要创建的环境的目录 install_python,开始先判断了不能用虚拟环境创建自己,clear参数清除环境下的lib库。使用sys.prefix找到python安装路径,还有一个real_prefix和base_prefix这俩路径官网没查到什么意思 创建新环境的lib文件夹,fix_lib64是为了兼容一些别的环境lib文件夹命名不同,咋不开始就定好。使用os库找到标准库的目录stdlib_dirs.然后将标准库文件软连接到新环境的lib下,copy_file分析了是软连接然后找到真实文件,连接到真实文件上. 还有一个REQUIRED_MODULES必要库,先判断这些必要库是否在标准库里边,不在通过imp.find_module找到,同样添加软连接到lib目录.这个应该也是为了兼容吧.其中lib目录有单独的一套,卧槽 我只能说这是python的坑吗,我觉得肯定不是作者特意写好多。(具体不了解不同系统有啥区别也不想看) 创建lib目录下的site-packages,site又是一套我查.include也是软连接 bin目录python二进制复制,那么多代码都是不同py实现的结果,其实就一句copy.不是windows解析器二进制还有带版本号的。然后测试了一把解析器能不能执行。最后返回新环境python的路径 install_distutils 安装 install_wheel 安装安装包的工具. install_activate 安装环境的启动退出脚本 install_python_config 安装python_config文件 上边两个模式基本相同,源文件在virtualenv_embedded下,通过编译到virtualenv.py文件里,然后安装的时候替换相关变量,然后生成新的文件。 最后再看看activate.sh文件如何启动 执行这个脚本的时候,先进行deactivate操作,相当于切换环境。主要就是判断之前的环境变量保存的几个变量是否存在,存在还原, 并删除。因为可以不存在,当前使用的system的python环境.ps1也还原 下边进行新环境变量的赋值。记录要切换的环境根目录,path加入环境bin目录, 删掉pythonHOME.更改ps1加上环境名,替换。pydoc重新绑定,变成了现在的pydoc。 然后就没了

Continue