Python 2/3下如何处理cjk编码的zip文件

今天项目中遇到了中文编码的zip文件,处理了蛮长时间,所以记录下,以免下次踩坑。

Python2下

Python2中读取zip文件,zipfile.ZipInfo的filename类型是str,基本上类似于python3中的bytes,即可以被decode为unicode。

所以,要处理中文,只需要将文件名按照编码decode成unicode就好。

1
2
3
4
5
6
7
8
import zipfile

fpath = '/path/to/zip.zip'
zfile = zipfile.ZipFile(fpath, 'r')
for fileinfo in zfile.filelist:
print fileinfo.filename.decode('gb18030')
# 如果要更加详细的区分bytes/str/unicode的语义
print bytes(fileinfo.filename).decode('gb18030')

Python3下

Python3中,Language encoding flag (EFS)如果是1,则按照utf8来处理文件编码,EFS如果为0,则直接按照cp437解码文件名。这是标准直接规定的。

但是,很多软件在制作zip压缩包的时候,直接使用gb18030或者其他非标准编码格式来编码文件名,所以我们还得将文件名反转为bytes,然后再使用对应的编码方式解码:

1
2
3
4
fpath = '/path/to/zip.zip'
zfile = zipfile.ZipFile(fpath, 'r')
for fileinfo in zfile.filelist:
print(fileinfo.filename.encode('cp437').decode('gb18030'))

阅读更多

How to use mysql-connector-python 2.1.5 on Django 1.10?

MySQL Connector/Python currently not available from PyPI

When you want use mysql-connector-python as db backend in Django, the first thing you noticed is that the latest version of mysql-connector-python on PyPI is 2.0.4, but official version is 2.1.5. The official developer explained this.(But why not host mysql-connector-python on PyPI?!). so, you can bypass this problem. Add follow line into requirements.txt:

https://dev.mysql.com/get/Downloads/Connector-Python/mysql-connector-python-2.1.5.tar.gz#egg=mysql-connector-python

when you configured Connector/Python Django Backend, and run python manage.py migrate , you will meet error:

DatabaseError: Data truncated for column ‘applied’ at row 1

This is because mysql.connector.django cannot handle datetime with timezone. You need patch 93c7b38. when you fix this, you must drop all table, and re-run python manage.py migrate, you will meet another error:

File “/path/to/venv/lib/python3.5/site-packages/mysql/connector/django/operations.py”, line 223, in bulk_insert_sql
return “VALUES “ + “, “.join([items_sql] * num_values)
TypeError: can’t multiply sequence by non-int of type ‘tuple’

can’t multiply sequence by non-int of type ‘tuple’

This is because bulk_insert_sql ‘s third argument changed from int to list of placeholder rows, since Django 1.9. You need another patch, patch 8dab00b. (Of cause, we doesn’t drop support of Django 1.6)


阅读更多

Django的MySQL Driver配置

之前写过一篇文章《Django@Python3添加MySQL/MariaDB支持》,现在Django对MySQL的支持已经很好了,现在就说一说最佳实践吧。

PEP 249 - Python Database API Specification v2.0规定了Python的数据库API。主要有三种API实现:

  • MySQLdb 是Andy Dustman开发的、使用原生代码/C语言绑定的驱动,它已经开发了数十年。
  • mysqlclient 是MySQLdb的一个支持Python3的fork,并且可以无缝替换调MySQLdb。mysqlclient目前是MySQL在Django下的推荐选择。
  • MySQL Connector/Python 是Oracle写的,纯Python实现的客户端库。

以上所有的驱动都是线程安全的,且提供了连接池。MySQLdb 是唯一一个不支持Python3的。

如果你使用mysqlclient(推荐此方式)

settings.py中的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Database
# https://docs.djangoproject.com/en/1.10/ref/settings/#databases

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #数据库引擎
'NAME': 'test', #数据库名
'USER': 'root', #用户名
'PASSWORD': 'root', #密码
'HOST': '', #数据库主机,默认为localhost
'PORT': '', #数据库端口,MySQL默认为3306
'OPTIONS': {
'autocommit': True,
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}

第14行主要是为了防止警告:

(mysql.W002) MySQL Strict Mode is not set for database connection 'default'

当然,要在requirements.txt中添加对mysqlclient的依赖:

阅读更多

Python3.4+uWSGI for Django Website in VirtualEnv (CentOS)

Install Python 3.x

In CentOS, There is no Python3 rpm package in EPEL, RPMFusion, we must install Python 3.x by source. Download Python 3.4.0, and extract it.

wget https://www.python.org/ftp/python/3.4.0/Python-3.4.0.tar.xz
tar -xvf Python-3.4.0.tar.xz
cd Python-3.4.0

switch to Python-3.4.0, compile&install Python 3.4.0 (You are expected have installed gcc, make and sqlite-devel)

./configure
make
make install

As the result, you can see the path of Python 3.4.0 by command which python3.4 Thanks to Python 3.4.0, we needn’t install PIP.

Install virtualenvwrapper&Django

You can install virtualenvwrapper by PIP.(Require root privileges) pip install virtualenvwrapper Don’t forget add two lines to file .bashrc:

VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3.4
source /usr/local/bin/virtualenvwrapper.sh

Let it take effect:

阅读更多

PEP 3107 -- 函数注解[译]

本文是PIP 3137的翻译。

背景

Python 2.x系列缺乏一个标准的方式来说明一个函数的参数和返回值,各种工具和库的出现填补了这一空白。一些工具使用了“PEP 318”中的装饰器,而其他的工具则去解析函数的文档注释,寻找注解。 在这一点上,众多已存在的机制和语法造成了很大的混乱。本PEP的目的是提供一个单一的,标准的方式指定这些信息,减少这些混乱。

函数注解的基础知识

在仔细讨论Python 3.0的函数注解的细节之前,首先让我们大致讨论下注解是什么、不是什么:

  1. 函数注解,无论是对参数的还是对返回值的函数注解,完全是可选的。

  2. 函数注解无非是一种方法,用来在编译时将任意Python表达式和函数的不同部分关联起来。就这点而言,Python并没有给注解赋予特殊的意义和重要性。Python仅仅让这些表达式可以被访问而已,以一种像本文的“访问函数注解”中描述的方法。注解对含义产生作用的唯一方式是当它们被第三方库解释的时候。这些注解的使用者可以用这些函数注解做他们想做的任何事情。例如,一个库可以利用字符串类型的注解来提供改进过的帮助信息:

    1
    2
    3
    4
    def compile(source: "something compilable",
    filename: "where the compilable thing comes from",
    mode: "is this a single statement or a suite?"):
    ...

    另一个库可以用来提供Python函数和方法的类型检查。这个库可以使用注解来说明函数的预期输入和返回值的类型:

    1
    2
    def haul(item: Haulable, \*vargs: PackAnimal) -> Distance:
    ...

    然而,不论是第一个例子中的字符串还是第二个例子中的类型信息,它们自己没有任何含义;含义来自第三方库。

  3. 根据第二点,该PEP不会试图引入一种标准的语义,即使是为那些内置类型。这个工作留给第三方库。

语法

参数

对参数的注解跟随着参数名,采用了一种可选表达式的形式:

1
2
def foo(a: expression, b: expression = 5):
...
阅读更多