# Python共享运行环境
# 运行环境介绍
新浪云 Python 应用运行于沙箱环境之中,前端负载均衡会根据负载在后端的多个节点中选择一个来处理 HTTP 请求。新浪云 Python 应用支持标准 WSGI 应用。
# 请求处理
新浪云的负载均衡会使用请求的域名来决定处理的应用。比如 http://your_app_name.applinzi.com
的请求会被路由给名为 your_app_name
的应用来处理。
每个应用可以同时运行多个版本,版本以数字为标示,默认版本为 1。如果需要访问非默认版本,需要在域名的前面加上版本号作为子域名: http://version.your_app_name.applinzi.com
。
默认 URL 符合以下规则的请求会作为静态文件处理:
- /static/*
- /favicon.ico
其他所有请求,都被路由到 /index.wsgi:application
,即应用根目录 index.wsgi
文件,名为 application
的 callable
,不可修改。
application 使用下列方式创建:
sae.create_wsgi_app(app)
将标准 wsgi 应用封装为适宜在新浪云上运行的应用:
import sae
def app(environ, start_response):
# Your app
...
application = sae.create_wsgi_app(app)
所有请求的最大执行时间为 300s ,超过该时间的请求会被系统强制结束,可能会导致返回 502。
对于每个应用的请求,系统会为其维护一个队列,如果出现请求在一定的时间里得不到处理,服务器会自动给该应用增加 instance。如果某一个 instance 在一段时间里没有任何请求,会被系统回收。
# 基本环境
Python 运行环境使用的是 Python 2.7.9。
- 仅支持运行纯 Python 的应用,不能动态加载 C 扩展,即.so,.dll 等格式的模块不能使用
- 进程,线程操作受限
- 本地文件系统只读。应用可以读取本应用目录,Python 标准库下的内容,如需读写临时文件建议使用 StringIO 或者 cStringIO 来替代。
说明
可以使用独享的python环境规避以上的限制。
Python 默认的模块搜索路径为:当前目录 > 系统目录。添加模块搜索目录的方法为:
import sys
sys.path.insert(0, your_custom_module_path)
请注意
Python 当前目录下的子目录只有包含__init__.py 才会被 Python 认为是一个 package,才可以直接 import。
用户可以上传和使用 .pyc
文件,注意 .pyc
文件必须是 python2.7.9
生成的,否则无效。
Python 运行环境设置了一些自定义的环境变量,这些环境变量可以通过 os.environ 这个 dict 获取。
- APP_NAME:应用名
- APP_VERSION: 当前应用使用的版本号
- SERVER_SOFTWARE: 当前 server 的版本(目前为 direwolf/0.1)。 可以使用这个环境变量来区分本地开发环境还是在线环境,本地开发环境未设置这个值。
# 创建应用
- 登录云应用管理系统 (opens new window),点击“+创建应用”;
- 开发语言选择Python,运行环境选择“共享环境”,选择一个代码的管理方式,即可快速创建一个Python的共享环境。
# Hello, world!
以一个简单的 hello world 应用介绍一下一个 Python 应用在新浪云上的创建和部署过程。
# 准备代码
以应用名为helloworld
例,下面部分代码中需要修改这个应用名为你创建的应用名。
目录下准备两个文件:
在目录下创建应用配置文件 config.yaml ,内容如下:
name: helloworld
version: 1
- name表示应用的名称,请换为你创建时指定的应用名;
- version 表示应用的版本,请换位你创建的版本。
创建应用的代码入口文件 index.wsgi ,内容如下:
import sae
def app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello, world!']
application = sae.create_wsgi_app(app)
新浪云上的 Python 应用的入口为 index.wsgi:application ,也就是 index.wsgi
这个文件中名为 application
的 callable object
。在 helloworld
应用中,该 application
为一个 wsgi callable object
。
# 上传代码
# 访问网站
通过浏览器访问应用可以看到输出的hello world:
# 使用Web开发框架
说明
以下所有的示例代码的完整版本都可以在我们的 Github repo (opens new window)中获得。
# Django
目前新浪云 Python 运行环境中预置了多个版本的 Django,默认的版本为 1.2.7,在本示例中我们使用 1.4 版本。
创建一个 Django project:mysite。
jaime@westeros:~/pythondemo$ django-admin.py startproject mysite
jaime@westeros:~/pythondemo$ ls mysite
manage.py mysite/
创建应用配置文件 config.yaml ,在其中添加如下内容指定使用的Django版本:
libraries:
- name: "django"
version: "1.4"
创建文件 index.wsgi,内容如下:
import sae
from mysite import wsgi
application = sae.create_wsgi_app(wsgi.application)
最终的目录结构如下:
jaime@westeros:~/pythondemo$ ls
config.yaml index.wsgi manage.py mysite/
jaime@westeros:~/pythondemo/1$ ls mysite
__init__.py settings.py urls.py views.py
部署代码,访问 http://<your-application-name>.applinzi.com
,就可看到 Django
的欢迎页面。
示例代码下载:
- 本示例完整代码:下载代码 (opens new window)
- Django1.2.7版本示例完整代码:下载代码 (opens new window)
以下说明一些在使用Django的过程中会碰到的问题。
# 处理用户上传文件
在 setttings.py 中添加以下配置:
# 修改上传时文件在内存中可以存放的最大 size 为 10m
FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760
# 新浪云的本地文件系统是只读的,修改 django 的 file storage backend 为 Storage
DEFAULT_FILE_STORAGE = 'sae.ext.django.storage.backend.Storage'
# 使用 media 这个 bucket
STORAGE_BUCKET_NAME = 'media'
# ref: https://docs.djangoproject.com/en/dev/topics/files/
说明
需要开启Storage服务,并创建一个名称为media的bucket,Storage的操作请参考Storage服务说明
# 发送邮件
settings.py 中添加以下配置,即可使用新浪云的mail
服务来处理 django 的邮件发送:
ADMINS = (
('administrator', 'administrator@gmail.com'),
)
# ref: https://docs.djangoproject.com/en/dev/ref/settings/#email
EMAIL_BACKEND = 'sae.ext.django.mail.backend.EmailBackend'
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'sender@gmail.com'
EMAIL_HOST_PASSWORD = 'password'
EMAIL_USE_TLS = True
SERVER_EMAIL = DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
说明
需要开启Mail服务,Mail操作请参考邮件服务说明
# 数据库的主从读写
参见 Django 官方文档 Multiple databases (opens new window)。
# 如何 syncdb 到线上数据库
在本地开发环境中,如下配置数据库,即可执行 python manage.py syncdb
直接 syncdb
到线上数据库。
# 线上数据库的配置
MYSQL_HOST = 'w.rdc.sae.sina.com.cn'
MYSQL_PORT = '3307'
MYSQL_USER = 'ACCESSKEY'
MYSQL_PASS = 'SECRETKEY'
MYSQL_DB = 'app_APP_NAME'
from sae._restful_mysql import monkey
monkey.patch()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': MYSQL_DB,
'USER': MYSQL_USER,
'PASSWORD': MYSQL_PASS,
'HOST': MYSQL_HOST,
'PORT': MYSQL_PORT,
}
}
# 如何 serve admin app 的静态文件
方法一:
修改 settings.py
中的 STATIC_ROOT
为应用目录下 static
子目录的绝对路径。
运行 python manage.py collectstatic
将静态文件收集到应用的 static
子目录下。
修改 config.yaml
,添加对 static
文件夹下的静态文件的 handlers
。
handlers:
- url: /static
static_dir: path/to/mysite/static
方法二:
在开发调试(settings.py 中 DEBUG=True
)过程中,可以将 staticfiles_urlpatterns (opens new window) 加到你的 URLConf,让 Django 来处理 admin app 的静态文件:
# urls.py
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
#...
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)),
)
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()
由于新浪云默认 static 为静态文件目录,需要修改 config.yaml,添加任意一条规则覆盖默认行为:
handlers:
- url: /foo
static_dir: foo
可以参考Django的文档:
- https://docs.djangoproject.com/en/1.4/ref/contrib/staticfiles/ (opens new window)
- https://docs.djangoproject.com/en/1.4/howto/deployment/wsgi/modwsgi/#serving-the-admin-files (opens new window)
# Flask
以下示例演示如何使用Flask框架,在代码目录下放置index.wsgi和myapp.py文件。
index.wsgi
import sae
from myapp import app
application = sae.create_wsgi_app(app)
myapp.py
import MySQLdb
from flask import Flask, g, request
app = Flask(__name__)
app.debug = True
from sae.const import (MYSQL_HOST, MYSQL_HOST_S,
MYSQL_PORT, MYSQL_USER, MYSQL_PASS, MYSQL_DB
)
@app.before_request
def before_request():
g.db = MySQLdb.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS,
MYSQL_DB, port=int(MYSQL_PORT))
@app.teardown_request
def teardown_request(exception):
if hasattr(g, 'db'): g.db.close()
@app.route('/')
def hello():
return "Hello, world! - Flask"
@app.route('/demo', methods=['GET', 'POST'])
def greeting():
html = ''
if request.method == 'POST':
c = g.db.cursor()
c.execute("insert into demo(text) values(%s)", (request.form['text']))
html += """
<form action="" method="post">
<div><textarea cols="40" name="text"></textarea></div>
<div><input type="submit" /></div>
</form>
"""
c = g.db.cursor()
c.execute('select * from demo')
msgs = list(c.fetchall())
msgs.reverse()
for row in msgs:
html += '<p>' + row[-1] + '</p>'
return html
# Bottle
以下示例演示如何使用Bottle框架,在代码目录下放置index.wsgi文件。
from bottle import Bottle, run
import sae
app = Bottle()
@app.route('/')
def hello():
return "Hello, world! - Bottle"
application = sae.create_wsgi_app(app)
# web.py
以下示例演示如何使用web.py框架,在代码目录下放置index.wsgi文件。
import os
import sae
import web
urls = (
'/', 'Hello'
)
app_root = os.path.dirname(__file__)
templates_root = os.path.join(app_root, 'templates')
render = web.template.render(templates_root)
class Hello:
def GET(self):
return render.hello()
app = web.application(urls, globals()).wsgifunc()
application = sae.create_wsgi_app(app)
# Tornado
以下示例演示如何使用Tornado框架,在代码目录下放置index.wsgi文件。
import tornado.wsgi
import sae
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world! - Tornado")
app = tornado.wsgi.WSGIApplication([
(r"/", MainHandler),
])
application = sae.create_wsgi_app(app)
# 外网访问
直接使用 urllib, urllib2、httplib 或者 socket 模块访问网络资源即可。
# 出口IP
请参考出口和入口IP。
# 日志系统
# 调试日志
打印到 stdout 和 stderr 的内容会记录到应用的日志中心中,所以直接使用 print
语句或者 logging
模块来记录应用的日志即可。
日志内容在 『应用管理中心 / 日志及监控 / 日志中心/ HTTP / 调试日志』 中查看:
# 静态文件日志
静态文件的日志单独记录,从『应用管理中心 / 日志及监控 / 日志中心/ HTTP / Alert日志』分类可以查询:
请注意
logging 默认设置的 level 是 WARNING,也就是 level >= WARNING 的消息才会被输出。
# 应用缓存
新浪云 Python 运行环境会对应用导入的模块(包括 index.wsgi)进行缓存,从而缩短请求响应时间,对于缓存了的应用,请求处理只是取出 index.wsgi 中 application 这个 callable 并调用。
# 应用配置
应用程序的配置文件为应用目录下的 config.yaml
文件。
# 使用预装模块
# 如何使用
Python 环境中已经预装了很多的第三方模块,可以直接使用:
- 对于存在默认版本的第三方模块,如果没有在 config.yaml 中配置,将使用对应模块的默认版本;
- 对于没有默认版本的模块,在应用的 config.yaml 文件中添加 libraries 段,指定你需要用的预装模块以及其对应的版本。 name 为模块的名称, version 为需要使用的版本,这两个字段为必填字段。
例如:
libraries:
- name: django
version: "1.4"
- name: numpy
version: "1.6.1"
# 当前预装的第三方模块列表
名称 | 支持的版本列表 | 默认版本 |
---|---|---|
django | 1.2.7, 1.4, 1.5, 1.8.3 | 1.2.7 |
flask | 0.7.2 | 0.7.2 |
flask-sqlalchemy | 0.15 | 0.15 |
werkzeug | 0.7.1 | 0.7.1 |
jinja2 | 2.6 | 2.6 |
tornado | 2.1.1, 2.4.1, 3.1.1 | 2.1.1 |
bottle | 0.9.6 | 0.9.6 |
sqlalchemy | 0.7.10, 0.9.7 | 0.7.10 |
webpy | 0.36 | 0.36 |
PIL | 1.1.7 | 1.1.7 |
MySQLdb | 1.2.3 | 1.2.3 |
numpy | 1.6.1 | 无 |
lxml | 2.3.4 | 无 |
PyYAML | 3.10 | 3.10 |
misaka | 1.0.2 | 无 |
matplotlib | 1.1.1 | 无 |
PyCrypto | 2.6 | 无 |
py-bcrypt | 0.2 | 无 |
greenlet | 0.4.0 | 0.4.0 |
gevent | 1.0rc2 | 1.0rc2 |
markupsafe | 0.15 | 无 |
bitarray | 0.8.0 | 无 |
请注意
默认版本为“无”的模块必须在config.yaml中手工指定才可以使用。
# 添加第三方依赖包
除了使用新浪云上已经预装的模块之外,您还可以通过以下方式给自己的应用添加第三方依赖包。
# 如何添加
- 首先,在应用的根目录下创建一个第三方依赖包目录
vendor
;
mkdir vendor
- 调用 pip 命令安装依赖包,使用其 -t 选项指定第三方包的安装目录。
$ pip install -t vendor PACKAGE ...
- 将 vendor 目录和应用的代码一起提交,即可在应用代码里使用安装的第三方依赖包了。
关于PIP版本
需要 pip 6.0.0 或者更高版本
如果依赖包安装的目录名不为 vendor
,你需要在 index.wsgi
文件的最开始,添加以下代码,将目录加入到 sys.path
中。
import sae
sae.add_vendor_dir('路径')
# 注意:以上代码得放在 index.wsgi 的最前面,所有其它代码之前。
函数的原型为:
sae.add_vendor_dir(dir)
- 将
site
目录或者virtualenv
目录加入到sys.path
中 - 参数dir:
site
目录或者virtualenv
目录的相对路径(相对于应用的根目录)
TIP
- 部分第三方库已经包含在默认搜索路径中,可以不在 config.yaml 中指定直接使用;
- 仅为兼容性考虑保留,不推荐使用,请在 config.yaml 明确配置。
# 静态文件处理
在应用目录下配置config.yaml
如下的文件内容:
handlers:
- url: /robots.txt
static_path: robots.txt
- url: /favicon.ico
static_path: favicon.ico
- url: /static/
static_path: static
上述的配置表示:
- http://xxxx.applinzi.com/robots.txt在根目录下找
robots.txt
文件 - http://xxxx.applinzi.com/favicon.ico在根目录下找
favicon.ico
文件 - http://xxxx.applinzi.com/static/xxxx.txt去根目录下的static目录下找xxxx.txt文件
url 为 URL 的前缀,static_path 为静态文件所在的目录(相对于应用目录)。
当请求的url
为目录时,服务器会首先尝试static_path
下的 index.html
,当 index.html
文件存在时,返回index.html
的内容,否则返回404
页面。
TIP
- 如果 config.yaml 中没有设置静态文件相关的 handlers,系统会默认将 /static 为前缀 的 URL 转发到应用目录下的 static 目录;
- 仅为兼容性考虑保留,不推荐使用,请在 config.yaml 明确配置。
# gzip 压缩
可以从config.yaml文件中配置压缩选项,例如:
handlers:
- url: /static/
gzip: on
- url: /a-big-file.txt
gzip: on
表示所有请求/static/下的文件或者/a-big-file.txt都开启gzip压缩。
url 为 URL 的前缀。
请注意
注意,当客户端支持 gzip(HTTP 请求的 Accept-Encoding 中包含 gzip)时,服务端才会开启压缩。
# 本地开发环境
本地开发环境仅为应用开发便利之用,对新浪云 Python 环境的模拟并不完全。
# 安装
直接使用 pip 或者 easy_install 安装 sae-python-dev 包即可。
或者可以选择从 github 下载源码安装。
$ git clone https://github.com/sinacloud/sae-python-dev-guide.git
$ cd sae-python-dev-guide/dev_server
$ python setup.py install
# 基本使用
进入应用的本地开发目录,也就是 index.wsgi 和 config.yaml 所在的目录。运行如下的命令启动测试 server:
$ dev_server.py
MySQL config not found: app.py
Start development server on http://localhost:8080/
访问 http://localhost:8080 端口就可以访问你的应用了。
# 使用 MySQL 服务
首先配置好 MySQL 本地开发 server。然后使用 –mysql 参数运行 dev_server.py。
$ dev_server.py --mysql=user:password@host:port
现在你可以在应用代码中像在新浪云线上环境一样使用 MySQL 服务了。 dev_server.py 默认使用名为 app_应用名 的数据库
# 使用 Storage 服务
使用 –storage-path 参数运行 dev_server.py。
$ dev_server.py --storage-path=/path/to/local/storage/data
本地的 Storage 服务使用以下的目录结构来模拟线上的 Storage。
storage-path/
domain1/
key1
key2
domain2/
domain3/
–storage-path
配置的路径下每个子文件夹会映射为 Storage 中的一个 domain, 而每个子文件夹下的文件映射为 domain 下的一个 key,其内容为对应 key 的数据。
说明
为方便调试,dev_server 自带的 sae.storage 在某个 domain 不存在的情况下会自动创建该 domain。 线上环境中的 domain 需要在新浪云后台面板中手动创建。
# 使用 pylibmc
dev_server 自带了一个 dummy pylibmc,所以无须安装 pylibmc 就可以直接使用 Memcached 服务了。 该模块将所有的数据存贮在内存中,dev_server.py 进程结束时,所有的数据都会丢失。
# 使用 KVDB
KVDB 默认数据存在内存中,dev_server.py 进程结束时,数据会全部丢失,如果需要保存数据, 请使用如下命令行启动 dev_server.py。
$ dev_server.py --kvdb-file=/path/to/kvdb/local/file
# 可用插件
# 新浪云 Python Shell
新浪云 Python Shell 是一个 wsgi
中间件,提供了一个在线的 interactive shell
,便于在线调试 app,查看系统信息等。(由 shellpy (opens new window) 修改而来)。
原型:
class sae.ext.shell.ShellMiddleware(app, password=None)
- app:你的应用 callable
- password: 可选,登录 shell 时需要输入的口令,用于保护 shell 不被非法访问。
# 使用步骤
- 开启Memcached服务;
- 修改 index.wsgi,启用 shell 插件,示例如下:
import sae
from sae.ext.shell import ShellMiddleware
def app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return ['Hello, world!']
application = sae.create_wsgi_app(ShellMiddleware(app))
访问地址 https://<your-app-name>.applinzi.com/_sae/shell
,根据提示输入你设置的口令即可。
说明
以上示例代码没有设置口令,直接访问即可,上线后请务必删除,以防网站的安全问题。
# 示例
# 常见问题
# 如何调试
复杂程序建议您本地调试成功后,再上传运行。
新浪云 Python 版本为 2.7.3,本地调试时注意不要使用高于此版本的Python。
如果你使用内置的第三方库,本地调试时最好使用同样的版本。
对于50X
页面,如果异常被web框架捕获,则需要打开web框架的调试开关,查看详细的异常信息。如果异常被Python Server捕获,Python Server会直接在浏览器中打印出异常。
说明
在header已经发出的情况下,异常在浏览器中可能显示不出来,请查看日志。
# 没有我要使用的包怎么办
- 对于纯python的package,参考添加第三方依赖包
- 对于含有
c extension
的package,目前共享型Python环境还无法直接支持,如果需要这些package,请使用独享型Python运行环境。
# MySQL gone away问题
共享型MySQL连接超时时间为30s,不是默认的8小时,所以你需要在代码中检查是否超时,是否需要重连。
对于使用sqlalchemy的用户,需要在请求处理结束时调用 db.session.close() ,关闭当前session,将mysql连接还给连接池,并且将连接池的连接recyle时间设的小一点(推荐为60s)。
# MySQL InterfaceError: (-1, ‘error totally whack(xxx)’)
这个错误表示mysql返回的错误码是新浪云自定义的错误码,其中totally whack后面括号中的数字是具体的错误码。
你可以在共享MySQL文档中查询到相关错误码具体代表的信息。
# 如何区分本地开发环境和线上环境
可以通过判断环境变量中是否有SERVER_SOFTWARE
判断是否在云端环境,如果没有说明在本地开发环境。
if 'SERVER_SOFTWARE' in os.environ:
# SAE
else:
# Local
# 如何使用virtualenv管理依赖关系
当你的应用依赖很多第三方包时,可以使用virtualenv来管理并导出这些依赖包,流程如下:
首先,创建一个全新的Python虚拟环境目录ENV,启动虚拟环境。
$ virtualenv --no-site-packages ENV
$ source ENV/bin/activate
(ENV)$
可以看到命令行提示符的前面多了一个(ENV)的前缀,现在我们已经在一个全新的虚拟环境中了。
使用pip安装应用所依赖的包并导出依赖关系到requirements.txt。
(ENV)$ pip install Flask Flask-Cache Flask-SQLAlchemy
(ENV)$ pip freeze > requirements.txt
编辑requirements.txt文件,删除一些新浪云内置的模块,eg. flask, jinja2, wtforms。
使用dev_server/bundle_local.py工具,将所有requirements.txt中列出的包导出到本地目录virtualenv.bundle目录中。如果文件比较多的话,推荐压缩后再上传。
(ENV)$ bundle_local.py -r requirements.txt
(ENV)$ cd virtualenv.bundle/
(ENV)$ zip -r ../virtualenv.bundle.zip .
将virutalenv.bundle
目录或者virtualenv.bundle.zip
拷贝到应用的目录下。
修改index.wsgi
文件,在导入其它模块之前,将virtualenv.bundle
目录或者virtualenv.bundle.zip
添加到module
的搜索路径中,示例代码如下:
import os
import sys
app_root = os.path.dirname(__file__)
# 两者取其一
sys.path.insert(0, os.path.join(app_root, 'virtualenv.bundle'))
sys.path.insert(0, os.path.join(app_root, 'virtualenv.bundle.zip'))
到此,所有的依赖包已经导出并加入到应用的目录里了。
更多virtualenv
的使用可以参考其官方文档 (opens new window)。
请注意
- 请删除requirements.txt中的wsgiref==0.1.2这个依赖关系,否则可能导致 bundle_local.py导出依赖包失败。
- 有些包是not-zip-safe的,可能不工作,有待验证。 含有c扩展的package 不能工作。
# Matplotlib使用常见问题
Matplotlib使用了numpy,所以需要在config.yaml
文件里将numpy
和matplotlib
添加到libraries里(对应的版本请参看:使用预装模块)。否则会导致matplotlib
import失败。
从config.yaml中配置:
libraries:
- name: numpy
version: "1.6.1"
- name: matplotlib
version: "1.1.1"
新浪云环境不支持matplotlib的interative模式,所以无法使用 pyplot.show()
直接来显示图像,只能使用 pyplot.savefig()
将图像保存到一个输出流中(比如一个cStringIO.StringIO的实例中)。
如果想要在matplotlib中显示中文,可以使用以下任一方法。
# 方法一
import os.path
from matplotlib.font_manager import FontProperties
zh_font = FontProperties(fname=os.path.abspath('wqy-microhei.ttf'))
import matplotlib.pyplot as plt
plt.title(u'中文', fontproperties=zh_font)
# 方法二
import os
# 设置自定义字体文件所在目录路径,多条路径之间使用分号(:)隔开
os.environ['TTFPATH'] = os.getcwd()
import matplotlib
# 设置默认字体名
matplotlib.rcParams['font.family'] = 'WenQuanYi Micro Hei'
import matplotlib.pyplot as plt
plt.title(u'中文')
其中方法一适用于ttf和ttc字体,方法二适用于只适用于ttf字体
如果有 matplotlibrc
配置文件,请将该文件与index.wsgi
放在同一个目录下(默认的当前路径)。
# 设置基于主机的访问控制
Python运行环境目前无法通过config.yaml来配置基于主机的访问控制,用户如果需要这个设置,可以通过wsgi middleware来完成,示例代码如下:
def filter_middleware(app):
def _(environ, start_response):
remote_addr = environ.get('REMOTE_ADDR')
# 判断remote_addr是否在允许访问范围内
# ...
if ok:
return app(environ, start_response)
start_response('401 Unauthorized', [])
return ["<b>401 Unauthorized</b>",]
return _
# 给application加上访问控制的中间件
application = filter_middleware(application)