SQLAlchemy中如何设置数据库连接参数

我们的Python编写的服务程序使用了SQLAlchemy访问数据库系统(MySQL). 为了满足PCI DSS安全性合规的要求, 我们需要使用TLS v1.1或TLS v1.2来加密数据库连接.

在配置好了数据库服务器端的TLS以后, 我们还需要配置数据库客户端的参数. 对于MySQL客户端来说, 最少应该配置 TLS CA的路径. 我们使用了MySQL Connector/Python作为数据库连接驱动程序, 它支持的配置参数是 ssl_ca. 我们不是直接使用MySQL Connector/Python, 而是通过SQLAlchemy来调用的, 因此我们需要寻找SQLAlchemy中的配置.

在SQLAlchemy中, 与数据库连接相关的是其Engine对象. Engine的配置可以分为两类. 第一类是对于SQLAlchemy而言的, 与底层的数据库驱动程序无关的; 第二类是特定于底层的数据库驱动程序的. 第一类主要与连接池, 字符编码等有关. 因此, 我们所需要的ssl_ca属于第二类的配置.

SQLAlchemy提供了三种方式来提供特定于数据库驱动程序的参数设置方式.

方式一: 附加于连接字符串之后.

mysql+mysqlconnector://user:password@host:port/dbname?ssl_ca=/etc/pki/ca …

Continue Reading

Python Debugger pdb with Examples

Debugger概述

在开发环境中,使用IDE集成的Debugger(调试工具)进行Debug,能帮助我们开发人员看到代码运行时的状态,对于排查疑难问题,很有帮助。一般来说,Debugger允许我们设置断点,让代码执行到断点时暂停,以便于我们查看断点附近的状态;然后以单步执行的方式,一次只执行一条语句,以便于我们观察状态的变化;也允许我们进入到调用函数内,跟踪函数内代码执行的状态。Debugger还提供更多的调试设置选项,快速地忽略其他代码的执行或从很深的调用堆栈中跳出来,让我们可以关注问题点。

一般来说,IDE的debugger是基于命令行的debugger的。直接使用命令行,一般有两种情况:

  1. 在不能使用IDE方式时,代替IDE进行debugger。比如,在集成测试环境中,服务器没有提供GUI用户界面,不能运行开发环境IDE。这时可以使用远程debugger,或者命令行方式的debugger。
  2. 脚本化调试过程。对于某些复杂的调试场景,基于命令行debugger编写调试脚本,提高调试效率。

本文介绍的是Python的命令行debugger工具包pdb。

如何进入Debugger

假设我们有一个脚本 example.py 需要调试,

python -m pdb example.py

这样会执行到脚本的第一行代码并停顿下来。

pdb 本质上是一个Python的模块 …

Continue Reading

在 RHEL 7 上安装 Selenium Python 环境

本文介绍在RHEL上安装 Selenium Python环境,执行无图形界面的浏览器自动化任务。

虚拟的图形界面 xvfb 或 xvnc

Linux 环境下使用虚拟的显示来运行普通版本的Firefox 或 chrome 浏览器。网上一般会推荐使用 xvfb (X virtual framebuffer),比如:

  1. http://scraping.pro/use-headless-firefox-scraping-linux/
  2. https://stackoverflow.com/questions/10060417/python-firefox-headless
  3. http://tobyho.com/2015/01/09/headless-browser-testing-xvfb/

在 RHEL 6中,可以下载到xvfb。但是在 RHEL 7中,已经不能下载到该包,可能是合并到了其他包中了。由于RHEL 6中的 firefox 及更底层的软件包对于 Selenium …

Continue Reading

mod_wsgi 的编译与安装

当我们使用了Linux操作系统发行版不包含的新版本的Python,我们会面临着需要使用相应版本的mod_wsgi的问题。比如Ubuntu 14.04 LTS 版本官方软件包里Python的最高版本是 3.4,相应的mod_wsgi也是和Python 3.4 编译的。当我们使用第三方的包把Python升级到了 3.6,相应地也需要把mod_wsgi升级。

办法是使用pip安装mod_wsgi。

$ sudo apt-get install python3.6-dev apache2-dev
$ . venv/bin/activate
$ pip install mod_wsgi

或者下载mod_wsgi的代码以后,本地编译安装

$ git clone https://github.com/GrahamDumpleton/mod_wsgi
$ cd mod_wsgi; git checkout <release-tag>
$ pip install .
# or
$ python setup.py …

Continue Reading

2017年 Instagram 把 Python2 升级到了 Python3

Instagram是特别流行的图片和视频分享社交平台,有超过6亿的注册用户,每天有超过4亿的活跃用户。因此,它是一个特别大规模的计算平台。它的主要开发语言是Python。Instagram是世界上最大的Python用户。

像PHP一样,Python也是属于入门容易的语言。最初Instagram选择Python的原因,和其他创业公司的技术选择一样,主要是因为初始团队的技术骨干很熟悉某种技术。而且Python也是很适合快速开发的语言。快速推出功能,比运行速度快要更重要。在架构合理的情况下,运行性能的问题可以通过添加服务器来缓解。

Python的运行慢的确给Instagram带来了服务器运营成本上的增加,他们也确实想过换成其他语言。Instagram属于Facebook,公司的另外一个主流语言是PHP。在调研时,把试点模块用PHP改写后,性能并没有特别大的改善。再加上Instagram的技术团队特别喜欢(熟悉)Python。于是他们改变了态度,与其抱怨,不如积极改善。既然决定了继续留在Python阵营,那么就要跟随Python社区,使用最新版本的Python,并回报社区。全面升级到Python3成了顺理成章的事情(Python3相对于Python2有很多新的特性)。

Python2与Python3并不兼容。Instagram前后花了近一年(10个月)的时间,通过小步快跑的方式,在不影响用户的情况下完成了迁移。

迁移过程中,他们主要做了哪些工作呢?

第一阶段,约3个月时间,大规模的代码修改,以及替换掉不兼容的第三方库。

第二阶段,约2个月时间 …

Continue Reading

Python中模块的循环引用

一般来说,在Python中模块的循环引用不是什么好的代码风格。但有时候这很难避免。比如有两个模块a和b,各表达一个业务逻辑,随着业务的发展,a开始依赖于b,因此,在a中引入了模块b,且在a的代码中大量引入了b的调用;后来,业务继续发展,b中也需要调用使用a的逻辑,两个业务有交叉关联关系。消除两个模块的循环依赖优先级并不高。

在 Python 3.5 时,还支持了 relative import。该问题的提出是在 relative import circular problem, 且解决方案为 Modify IMPORT_FROM to fallback on sys.modules 。Relative import 指的是 from a import b 这种形式的模块import。

Relative import的逻辑在 __import__ 中很早就实现了,但 IMPORT_FROM …

Continue Reading

Ubuntu 14.04 中升级到 Python 3.5/3.6

Ubuntu 14.04 官方的Python版本最高到Python 3.4,但是我们的代码开发环境是 Python 3.6, 代码中存在支持模块的循环相对引用,该功能在 Python 3.5 才引入,因此我们需要升级Python。

我们可以自己下载源代码,编译该版本的Python。但更方便的办法是使用一个知名的第三方包。在Ubuntu中,这是很常见的办法,其协议是 ppa。知名的 Python3.5, 3.6 ppa源是 fkrull/deadsnakes。

sudo add-apt-repository ppa:fkrull/deadsnakes
sudo apt-get update
sudo apt-get install python3.6

or use pyenv https://askubuntu …

Continue Reading

Python 计算金额

由于浮点数的二进制转换会丢失精度,对于金额的存储与计算,一般用Decimal十进制编码类型。

有两个问题需要考虑,一是舍入规则,二是保留小数点后几位。默认情况下是四舍五入,保留两位小数。

Decimal 的 quantize 方法能处理数字保留几位小数点的问题。

price = Decimal('8.014')
price2 = price.quantize(Decimal('.00'))
# price2: 8.01
balance = Decimal('200.105')
balance2 = balance.quantize(Decimal('.00'))
# balance2: 200.11

Continue Reading

Python sqlalchemy 数据类型转换

将字符串类型的数据存放到数据库中,是一个很常见的任务。在Python数据库开发中,我们经常使用sqlalchemy定义数据模型。多数情况下,不管模型中定义的数据类型是什么,我们都可以直接将字符串赋值给各字段,然后sqlalchemy会帮我们进行转换。 有时候,我们也需要自己做类型转换。比如,我们希望获得数据记录的变动情况,就需要比较输入字符串类型的数据和从数据库中查询到的数据记录。类型不一致,就不能准确地比较。本文介绍的类型转换方法,是基于模型定义中的数据类型,以及它们与Python类型的对应关系而实现的。

数据类型是很多的。本文只介绍最常见的需要转换的类型,即日期和数值。

数据例子

数据例子包含一个sqlalchemy 数据模型定义 和 一个输入数据。我们需要把全部是字符串类型的输入数据, 根据模型进行字段类型转换。

数据模型

class Project(Base):
        __tablename__ = 'project'
        id = Column(Integer, primary_key=True)
        project_name = Column(String)
        due_date = Column(Date)
        cost = Column(Numeric(13,2 …

Continue Reading

给venv增加额外的Python包路径

问题介绍

使用venv可以建立隔离的Python环境,比如 virtualenv 或 python3 -m venv可以创建venv。 这时,如果我们需要的某个包已经安装在了系统中,但并不在我们的venv的路径下,该怎么办才能加进来呢?

在网上搜索之后,我发现,这个问题有多种解决办法。最简单的办法是使用pth机制。

案例问题描述

我们已有venv环境 ~/venv, 现在想把 /var/lib/pyfoo/dist-packages 加入到路径中。 该路径下有我们需要的包 bar。

操作步骤

首先,创建pth文件 _venv_ext.pth, 其内容如下,

$ cat _venv_ext.pth
/var/lib/pyfoo/dist-packages

然后,将该文件放到 venv的 site-packages下,

$ mv _venv_ext.pth ~/venv/lib/python …

Continue Reading