分类:'编程随笔' 的所有文章

折腾 - 发芽网后台更新Python2.7.2, Django1.3, Pygments1.4, jQuery1.6.2

发芽网后台更新了:Django1.3, Python2.7.2,jQuery1.6.2,Pygments1.4

其中Pygments的更新带了更多的语法高亮支持,包含了许多人熟悉的AutoHotkey

话说,似乎是临时的,很多的国外网站都没法访问了,连ssh也不可用了,这些网站都是技术性网站,应该没问题的,加上vpn就可以访问了,奇怪的是,用vpn也访问不了twitter了,难道传说中的白名单制度开始试水了?Fuck GFW! @ 2011-08-21, 18:47:11

—————————————————————

最近有人在代码发芽网上留言问能不能加上AutoHotkey的高亮支持,瞄了一眼Pygments的新版本1.4,发现已经支持了,打算搞过来。另外发现发芽网后台的Django和Python以至于jQuery都老了,想起前几天看到阮一峰介绍新版jQuery性能的文章,据说快了很多,决定把这些一起更新一下,折腾开始了,且看一个业余的网页开发者会遇到多少问题。。。

1. 首先,参考以前的文章”configure your own python 2.5.2 on bluehost”安装Python2.7.2,下载编译安装,搞定。顺手改了.bashrc,这样下次ssh到服务器用的就是2.7了

2. 然后,下载easy_install的egg包,用 sh xxx.egg 安装完毕,然后,easy_install安装了发芽网依赖的库:django1.3, PIL, flup, MySQL-Python, Pygments1.4, markdown2, python-openid,为了用起来顺手,又安装了ipython

3. 然后,参考以前的文章Bluehost Django fastcgi配置, 静态(static)文件处理更改了t.fcgi,指向新的python库

4. 然后到后台杀死所有t.fcgi进程,网站立马不可访问了,500 Error或者干脆半天都不返回,杯具。

5. 查吧,一个个查,根据多次折腾的经验,觉得应该是t.fcgi里面出异常了。这个好办(现在说好办,当时也想了半天),因为t.fcgi也是python脚本,直接执行之,居然没有发现任何问题,突然发现,t.fcgi最上面一行,对,就是指定python可执行文件地址的地方,用的还是python2.5,sigh,亏我还在以前的文章里专门写过注意事项。

6. 再次杀死进程,打开网站,nnd,依然是挂的,再次执行t.fcgi,这次报了异常 - flup库没有安装,晕倒(前面步骤2里是全的,当时忘了装了),再次执行,没有啥问题了………中间由于每次fail都会发日志给我的邮箱,还遇上了bluehost发email的限制,不得不在Django配置文件里打开了Debug=True调试选项

7. 再次杀死进程,打开网络,tnnd,依然是挂的;好吧没关系,就放我换个姿势再来一次,在发芽网源文件目录底下,敲入python manage.py runserver,对,就是起了一个本地Django Server,果然起不来,但是可以看到异常了,看出来似乎是PIL里面出的问题,错误信息是MemoryError还提到了ctypes,肿么办?这个吓不倒我,Google之,发现这篇文章,里面说,打开$HOME/lib/python2.7/ctypes/__init__.py,找到CFUNCTYPE(c_int)(lambda: None),注释掉它就ok但是不知道到底为神马。我打开一看,里面居然有一段注释,意思是,写这几行代码的人也不完全清楚为什么要写这行代码:

# XXX for whatever reasons, creating the first instance of a callback
# function is needed for the unittests on Win64 to succeed.  This MAY
# be a compiler bug, since the problem occurs only when _ctypes is
# compiled with the MS SDK compiler.  Or an uninitialized variable?
CFUNCTYPE(c_int)(lambda: None)

8. 这样的神问题都碰上了,我像个小强一样挺了过来,注释掉这一行,居然,就搞定了~~~

9. 终于,发芽网可以打开了,世界和平了,王子和公主从此过上了幸福的生活~~~直到,我发现admin页面无法访问了

10. 这时候我大概已经患上了斯德哥尔摩综合症,看到这个问题,居然虎躯一震,精神焕发,查起了Django1.4的文档,发现,urls.py里面有个地方要改改了。这么快就搞定,很是乏味啊~

11. 终于成功的打开了admin页面,发现页面布局有些古怪,突然想起以前发的另一篇文章Bluehost上架设Django之Admin,原来admin_media还是指向以前安装的1.1的,删掉链接文件重新ln一下,搞定

12. 终于,看起来一切正常了,siteuptime服务告诉我说 back to normal 。。。咚咚呛

13. 然后发现代码发芽网贴代码以后,看起来就是一片漆黑,用chrome的developer tools验证了一下,原来所有的jQuery.ajax调用都会跑到异常分支里去,加上了几行代码发现报错 Unexpected token 。继续Google关键字Unexpected token和jQuery,发现stackoverflow上面有个帖子说这个事情,居然是个jQuery的bug?jQuery会把返回结果当成json进行eval,当然会有些问题啦,于是把所有的ajax调用里面都加上了一句 dataType: ‘text’ 之后,一切ok了

14. 至此,好像一切都好了,第二天,tianyi song同学给我写信,问我为什么代码发芽网不能用了?还给我发来了截图。来回交流了几次,发现我原来的代码里对Pygments的一个格式有严格依赖,在Pygments1.4里面这个格式有些改动,没办法,把Pygments源码里面html.py这个formatter改了几行,总算搞定了

15. 篇幅限制,省略细节问题十数条,还会遇到神马问题?期待~~~

经验总结

1. 不要怕,找到问题,细心分析,想各种方式去debug,搜索Google,大不了去看代码

2. 本地环境和部署的环境的一致性很重要,Service Engineer很重要啊,要想再更新的同时网络不下线,没有SE的支持是很困难的

3. 做个大网站,没有unit test也没有测试团队,那是不可能地~

btw, 或许有人问,搞这么多问题,就为了一个小小的网站,值吗?

值!兴趣是无价的,折腾是永恒的~~~在折腾中学习就是爽~~~!

  • Share/Bookmark

Python HTTP - Post a Binary File using urllib2

I was trying to post a png file to our internal webserver for some quick and dirty task, but Python keep throwing ascii encoding exception.

Then I search “post http binary urllib2″ and did found several options, like multipart/form-data and pycurl, but they need the webserver’s help to accomplish a simple file posting.

In the end I decide to dig into Python’s httplib and urllib2 to find out what’s going on, if that doesn’t work I will fallback to raw TCP socket solution.

Luckily I got the following solution that works like a charm:
1. set Content-Length header(of the file) before doing post
2. pass a opened file when doing post

Sample code:

Python语言: Python Post a Binary File using urllib2
import urllib2, os

image_path = "png\\01.png"
url = 'http://xx.oo.com/webserviceapi/postfile/'
length = os.path.getsize(image_path)
png_data = open(image_path, "rb")
request = urllib2.Request(url, data=png_data)
request.add_header('Cache-Control', 'no-cache')
request.add_header('Content-Length', '%d' % length)
request.add_header('Content-Type', 'image/png')
res = urllib2.urlopen(request).read().strip()
return res

  • Share/Bookmark

贴代码:从命令行卸载程序, Windows XP/Vista/Win7

主要写给自己用,因为天天都跟windows命令行打交道,装了个CCleaner就是因为它比windows自己的“添加/删除程序”要快。最近实现工作中要用到的东西,顺便做得更加通用一点,贴到这里。还挺方便的,因为命令行更快。

保存成u.py,然后如下运行:

D:\Documents\Dropbox\Coding\active>u apple
multiple matches, please choose:

  1  Apple Mobile Device Support
  2  Apple Software Update
  3  Apple Application Support

select a number, Ctrl+C to quit: 3

        Apple Mobile Device Support

press ENTER to uninstall, Ctrl+C to stop
Python语言: Command line uninstaller for Windows Applications
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#Author : Zhongfang Ren
#         yid: renzhongfang
#         email: realfun AT gmail.com
#         website: http://2maomao.com/blog/, http://fayaa.com
#Purpose: Command line uninstaller for windows XP(Vista and Win7 not tried yet)
#Date   : Wednesday, March 23, 2011, 10:42:34
#

import sys, os, getpass
import subprocess as exe
import _winreg as R

target = ''
if len(sys.argv) > 1:
  target = sys.argv[1]

uninstalls = []

for root in (R.HKEY_LOCAL_MACHINE, R.HKEY_CURRENT_USER):
  with R.OpenKey(root, "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") as key:
    keys = []
    i = 0
    while True:
      try:
        keys.append(R.EnumKey(key, i))
        i += 1
      except Exception as e:
        #print e
        break

    for k in keys:
      try:
        with R.OpenKey(key, k) as hkey:
          try:
            v = R.QueryValueEx(hkey, "DisplayName")
            v = str(v[0])
            if v.lower().find(target.lower()) >= 0:
              uninstalls.append((v, R.QueryValueEx(hkey, "UninstallString")[0]))
          except Exception as e:
            #print e
            pass
      except:
        pass

try:
  if not uninstalls:
    print "uninstall for %s not found" % target
  elif len(uninstalls) == 1:
    print
    print "\t%s" % uninstalls[0][0]
    print
    raw_input("press ENTER to uninstall, Ctrl+C to stop")
    exe.call(uninstalls[0][1])
  else:
    print "multiple matches, please choose:\n"
    i = 1
    for nu in uninstalls:
      print "%3d " % i, nu[0]#, '\t', nu[1]
      i += 1
    print
    val = 0
    while val <=0 or val > len(uninstalls):
      try:
        val = int(raw_input("select a number, Ctrl+C to quit: "))
      except ValueError:
        pass
    name, uninst = uninstalls[val-1]
    print
    print "\t%s" % name
    print
    raw_input("press ENTER to uninstall, Ctrl+C to stop")
    exe.call(uninst)
except KeyboardInterrupt:
  pass
finally:
  print

  • Share/Bookmark

一些有用的Python库

Update @ 2011-03-06, 15:02:57
你有没有使用过的觉得不错的Python库?请到这里跟大家分享:常用的 Python 库:请投票

——————————————————-

今天整理C盘,看到python还是2.6,就给更新到了2.7,再更新所有的site-packages过程中,搜到了这个网页:
http://wiki.python.org/moin/UsefulModules

网页中列出了一堆有用的库,其中有一些我曾经用过或者比较感兴趣的,选了一些混合我现在常用的lib列在下面:

Easy Install: easy_install 安装工具,下面提到的多数lib都能用easy_install lib_name进行安装

SQLAlchemy, SQLObject, Mysql-Python(Win32安装包):数据库访问,发芽网后台用到了Mysql-Python

CTypes - 直接调用dll中的函数,经常用来做Windows API的调用

WxPython - Python UI库,Ulipad就是基于这个

Ascii_table:在命令行界面中输出漂亮的表格

Python Imaging Library (PIL) :图片处理,发芽网的Captcha用到了这个

PyAudio:WAV文件读写,录音,用这个写过一个录音工具,还不错

HTTPLib2:非常好用的http工具,做cookie、put请求、header、错误处理等等很方便,可以做网络爬虫或者访问webservice的脚本

Psyco :只要简单的写下如下两句话,就能让你的python脚本快很多,在需要很多计算的脚本里很好用,求解华容道时试过,速度改进的不错,虽然最后还是没有达到要求,改用C++写了一个:

import psyco
psyco.full()

PyObjC: Python写ObjectiveC/cocoa程序作为一个遗憾放在这儿吧,要是支持iOS就好了

PyWin32 :针对win32常用的系统api做了很好的封装,用这个写过一个彩色命令行脚本

NumPy, SciPy, Matplotlib:科学计算的三神器,更多参见这里。有本在线的书:用Python做科学计算,旅居日本的hyry写的,值得一看

Py2exe: 把你的python脚本转成exe可执行程序,曾经用过,仅支持到python2.5所以最近没用过了

Django:使用最多的Python web framework,发芽网也是基于Django

lxml:XML文件处理的利器。最近两年有点儿烦HTML,改用json了

iPython: 更加好用的Python命令行交互环境

python-openid:Python下做OpenID,都得用这个,发芽网的OpenID支持也是基于这个做的

Pygements代码发芽网的高亮,用的就是这个库,略该,以适应直接复制粘贴的需求

nose:python下的测试驱动工具,曾经用过,很简洁。现在我用doctest更多一点

  • Share/Bookmark

Python urllib2的使用点滴: cookie, https, put, 500/403的处理

Update @ 2011-03-06, 13:46:08
刚刚发现了一个比urllib2更好用的库httplib2,可以比较简单的解决本文遇到的一些问题
http://code.google.com/p/httplib2/

————————————————————

最近用urllib2写了一个公司内部用的脚本

这个脚本要访问一个webservice,访问之前先要用https登陆拿到cookie再到另一个地方获取一个临时用的id

https登陆,获取cookie

首先是https登陆,这段很好写,以前写过校内网发帖机,轻车熟路,用cookielib的CookieJar加上HTTPCookieProcessor搞定,代码如下(其中那个超简单的lambda hack简直绝了:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import urllib, urllib2, sys, cookielib, re, os, json

cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
url_login = 'https://xxx.yahoo.com/login/'
body = (('username', '半瓶墨水'),
        ('password', '密码'),
        ('action', 'login'),)

print 'login to get cookies'
opener.open(url_login, urllib.urlencode(body))

处理HTTP 403/500 Exception

但是后面用cookie去拿id的时候,就老是告诉我403错误,然后opener就抛异常,想问题想到头大,后来发现这个服务访问成功不是返回200,而是403,所以看到403的时候不要管他,直接看body内容就行了,日,不知道为什么这么设计。

怎么办呢?查了一下urllib2的文档,发现可以继承一下HTTPCookieProcessor,自己做了一个NoExceptionCookieProcesser,后来的过程中发现webservice有时候返回400和500的时候body中包含有用的信息,一并处理了:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import urllib, urllib2, sys, cookielib, re, os, json
#suppress the 403/400/500 exception and return the body
class NoExceptionCookieProcesser(urllib2.HTTPCookieProcessor):
  def http_error_403(self, req, fp, code, msg, hdrs):
    return fp
  def http_error_400(self, req, fp, code, msg, hdrs):
    return fp
  def http_error_500(self, req, fp, code, msg, hdrs):
    return fp
 
cj = cookielib.CookieJar()
opener = urllib2.build_opener(NoExceptionCookieProcesser(cj))
url_login = 'https://xxx.yahoo.com/login/'
body = (('username', '半瓶墨水'),
        ('password', '密码'),
        ('action', 'login'),)

print 'login to get cookies'
opener.open(url_login, urllib.urlencode(body))

urllib2中用PUT进行请求

然后又发现一个问题,webservice在提交的时候要求用PUT方式,并且只接受json,urllib2默认只支持GET和POST,Google了一下,发现可以创建Request对象,然后更改它的请求方法(get_method)以及header,搞定:

request = urllib2.Request(url_ws, data="blablabla")
request.add_header('Content-Type', 'application/json')
request.add_header('Accept', 'application/json')
request.get_method = lambda: 'PUT'
result = opener.open(request).read().strip()

参考:http://stackoverflow.com/questions/111945/is-there-any-way-to-do-http-put-in-python

  • Share/Bookmark

下一页 »