文章背景
做app 消息推送
自己写sdk的缘由
有些只支持Python2 有些支持Python3 兼容,不支持3 的如果不太复杂就自己根据官方api文档写一个请求的,如果复杂就在直接用sdk ,这样只能用Python3 调用Python2。在很多代码中在Python2 环境中是不报错的但是在Python3中是报错的, 这就牵扯到Python3 Python2 中引入模块的问题;
python2,3 引入模块的相对 绝对路径等
在对这两种分布清楚的情况下,最好使用绝对路径,弄清楚的情况也最好使用绝对路径
Python中package 和普通包之间的区别
package 文件夹中多了一个init .py 的文件 ,有了这个文件Python就认为这个文件夹是一个package, package 是可以引入的但是普通文件夹是不可以的
init.py 文件是空的,只是用来告诉你 当前文件夹是个package.里面也可以添加代码,这些代码会在import 这个包的时候运行
所以,请你再你要import 文件所在的文件夹下面是有init.py 的(除非它在sys.path中的某个文件夹下面)
导入路径
from package.subpackage1 import foo1
package 是在根目录下的文件夹, 使用绝对路径导入
python的-m参数官方说法是:
Searches sys.path for the named module and runs the corresponding .py file as a script.
在下面的例子中,加上-m参数后,所运行的.py文件便会识别其顶层的package
创建完main.py之后,cd到项目的根目录,运行
python -m package
即可实现直接运行main.py,即直接运行了package这个包
如果你想直接运行package内的某个.py文件,比如foo1,则:
python -m package.subpackage1.foo1
当然,你要确保foo1中存在判断其是否是入口函数的逻辑,如下:
if __name__ == "__main__":
speak()
python2 缺省为相对路径,python3缺省为绝对路径导入
Python2 绝对路径导入
from __future__ import absolute_import
python2缺省会搜索上一级目录、上上级目录
解决方案
import platform
pver=platform.python_version()
pversion= int(pver.split('.')[0])
try:
if pversion==2:
print(1)
from .A import aa
else:
print(2)
from A import aa
except:
print(3)
from A import aa
异常处理
try:
from .A import aa
print(12)
except:
print(22)
from A import aa
总言之 要使用绝对路径,并且绝对路径和相对路径不要混用
http://blog.sina.com.cn/s/blog_5d0adef001017yq8.html
上面的这个不错
当我改友盟推送的 Python实例代码就的时候就修改的是成Python3 路径都改为了绝对路径
目前还没有解决遇到最大困难
当提供的sdk 比较复杂的时候 还是Python2 而项目使用的是python3 的时候 使用Python3 调用Python2的代码,这样就要维持两个环境。传递参数的时候会遇到这样的问题
- 参数有空格的问题
- 有汉字的时候(在windos系统上面这个问题解决不了,浪费了我一整天来解决编码问题,还是不可以的)
友盟推送
鉴于上面遇到的困难,再结合项目需求就把这个 python示例给重写为Python3 的。这里顺便说下,示例代码是有错误的,body里面添加数据的时候只能添加第一条数据,而且里面代码不够规范,有些代码的后面竟然有; (分号),这是我第一次遇见,如果从开始学习Python的时候看到这样的代码的时候肯定对对我照成影响的。
这是我项目的目录结构
调用的代码
import json
from push.umeng.umessage.pushclient import PushClient
from push.umeng.umessage.iospush import *
from push.umeng.umessage.androidpush import *
from push.umeng.umessage.errorcodes import UMPushError, APIServerErrorCode
from push.umeng.umessage.iosnotification import IOSNotification
#注意andorid和ios是不同的appkey和appMasterSecret。 在不同需求下换成各自的appkey。
appKey = "xxx"
appMasterSecret = "xxx"
# deviceToken = "xxx"
class UmengSend(object):
#android
@staticmethod
def sendAndroidUnicast(deviceToken, custom, ticker="", title="", text=""):
# 必填项
unicast = AndroidUnicast(appKey, appMasterSecret)
unicast.setDeviceToken(deviceToken)
unicast.setTicker(ticker)
unicast.setTitle(title)
unicast.setText(text)
unicast.goAppAfterOpen()
# unicast.setDisplayType(AndroidNotification.DisplayType.notification)
unicast.setDisplayType(AndroidNotification.DisplayType.message)
unicast.setCustomField(custom)
# unicast.setTestMode()
pushClient = PushClient()
ret = pushClient.send(unicast)
data = UmengSend.printResult(ret)
return data
@staticmethod
def printResult(ret):
response_data = dict()
response_data["http status code"] = ret.status_code
# print("http status code: %s" % ret.status_code)
if ret.text != "":
ret_json = json.loads(ret.text)
if ret_json["ret"] == IOSNotification.CONSTR_STATUS_SUCCESS:
if 'msg_id' in ret_json['data']:
response_data["msgId"] = ret_json['data']['msg_id']
# print("msgId: %s" % ret_json['data']['msg_id'])
if 'task_id' in ret_json['data']:
response_data["task_id"] = ret_json['data']['task_id']
# print("task_id: %s" % ret_json['data']['task_id'])
elif ret_json["ret"] == IOSNotification.CONSTR_STATUS_FAIL:
errorcode = int(ret_json["data"]["error_code"])
response_data["errorcode"] = errorcode
response_data["detail"] = APIServerErrorCode.errorMessage(errorcode)
# print("error Code: %s, detail: %s" % (errorcode, APIServerErrorCode.errorMessage(errorcode)))
return response_data
if __name__ == '__main__':
deviceToken = "xxx"
title = "nihao"
ticker = "成功了"
text = "我是杨"
custom = "我是custom"
UmengSend.sendAndroidUnicast(deviceToken, custom, ticker=ticker, title=title, text=text)
去官网获取deviceToken appkey,appMasterSecret 需要的值等,看文档来选择自己需需要的推送样式和模板
个推推送
个推推送有点复杂只支持Python2 的sdk ,这里想了一个办法用来调用Python2 的方法,但是这样遇到了两个现在没有解决的问题,空格, 还有编码问题
getui.py
# -*- coding: utf-8 -*-
import sys
import json
from igetui.igt_message import IGtAppMessage
from igetui.template.igt_link_template import LinkTemplate
from igt_push import IGeTui
from igt_push import *
from igetui.template import *
from igetui.template.igt_base_template import *
from igetui.template.igt_transmission_template import *
from igetui.template.igt_link_template import *
from igetui.template.igt_notification_template import *
from igetui.template.igt_notypopload_template import *
from igetui.igt_message import *
from igetui.igt_target import *
from igetui.template import *
from sys import argv
if sys.version < '3':
reload(sys)
sys.setdefaultencoding('utf-8')
HOST = 'http://sdk.open.api.igexin.com/apiex.htm'
APPKEY = "xxx"
APPID = "xxx"
MASTERSECRET = "xxx"
# CID = "xxx"
HOST = 'http://sdk.open.api.igexin.com/apiex.htm'
def get_message(content):
"""获取消息"""
message = IGtSingleMessage()
message.isOffline = True
message.offlineExpireTime = 1000 * 3600 * 12
message.data = get_template(content)
message.pushNetWorkType = 1
return message
def get_template(content):
"""获得模板"""
template = TransmissionTemplate()
template.transmissionType = 1
template.appId = APPID
template.appKey = APPKEY
template.transmissionContent = content
return template
def get_target(cid):
"""获得推送目标"""
target = Target()
target.appId = APPID
target.clientId = cid
return target
def pushMessageToSingle(cid, content):
"""进行推送"""
print content
push = IGeTui(None, APPKEY, MASTERSECRET, True)
message = get_message(content)
target = get_target(cid)
try:
ret = push.pushMessageToSingle(message, target)
print ret
except RequestException, e:
# print e
requstId = e.getRequestId()
ret = push.pushMessageToSingle(message, target, requstId)
print ret
print "jijijii"
import chardet
cid = argv[1]
# encoding_dict = chardet.detect(argv[2])
# content = argv[2].decode("ISO-8859-1").encode("utf8").decode("utf8")
# content = json.loads(argv[2])
# content = content.get("a").decode("ascii").encode("utf8").decode("utf8")
content = argv[2]
print content
pushMessageToSingle(cid, content)
# import chardet
getui_send.py 用于执行系统的命令来执行的Python2 代码
# coding: utf-8
import os
import json
import platform
the_platform = platform.system()
if the_platform == "Windows":
PYTHON2PATH = r"C:\Python27\python.exe"
elif the_platform == "Linux":
PYTHON2PATH = r"/bin/python"
current_path = os.path.dirname(os.path.abspath(__file__)) + "/"
NAME = current_path + "getui_send"
def execute_python2(cid, content, python2path=PYTHON2PATH, name=NAME):
# print content
cmd = python2path + " " + name + ".py " + cid + " " + content
print(cmd)
command = os.popen(cmd)
# print(command)
try:
print("in try")
# print(command.read())
result = command.readlines()
except Exception as ex:
print("in except")
print(ex)
result = list()
return result
if __name__ == "__main__":
pass
cid = "xxx"
# # cid = "f3263437f5ef90fe8ff9fdeda6c0c3e4"
# # content = u"'hello2 word'"
# content = "\"hello word好\""
# content = str("hellowordwww好erere各个".encode("utf8"))
# content = u"hello好"
# content = "hellowordwww好".encode("utf8").decode("utf8")
content = "hellowordwww好"
# content = repr("hellowordwww好".encode("utf8"))
# content = "hellowordwww好"
# dic_test = dict()
# dic_test["a"] = content
print(content)
result = execute_python2(cid, content)
print(type(result))
print(result)
想到一个问题,在有很多文件的时候
在有很多文件的时候,并且哪些都是2中环境才可以的话那就每个要用代码调用才能说是在Python2 的环境的。 在个推中出现不能使用中文还使用了很多别的文件,相当于只用是一个自己写的一个主要文件去调用Python2 环境 ,起的的还是Python 3 的问题,这里面的问题还是没有解决。最好的办法是把 本地的sdk自己改写为3的环境不然就才难受了,各种你想不到的bug就会出现。
别跑麻烦,
咨询了大神,上面这段话是有问题的,只要这个文件使用Python2的环境,那么这个文件使用的文件引入的文件都是使用的python2 的环境