Skip to content

Commit

Permalink
Fix circular reference bug
Browse files Browse the repository at this point in the history
  • Loading branch information
littlecodersh committed Mar 31, 2017
1 parent 0161489 commit 559063a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 38 deletions.
2 changes: 1 addition & 1 deletion itchat/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os, platform

VERSION = '1.3.4'
VERSION = '1.3.5'
BASE_URL = 'https://login.weixin.qq.com'
OS = platform.system() #Windows, Linux, Darwin
DIR = os.getcwd()
Expand Down
13 changes: 3 additions & 10 deletions itchat/storage/messagequeue.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,29 @@
import logging

try:
import Queue as queue
except ImportError:
import queue

from .templates import AttributeDict

logger = logging.getLogger('itchat')

class Queue(queue.Queue):
def put(self, message):
queue.Queue.put(self, Message(message))

class Message(dict):
class Message(AttributeDict):
def download(self, fileName):
if hasattr(self.text, '__call__'):
return self.text(fileName)
else:
return b''
def __getattr__(self, value):
value = value[0].upper() + value[1:]
return self[value]
def __getitem__(self, value):
if value in ('isAdmin', 'isAt'):
v = value[0].upper() + value[1:] # ''[1:] == ''
logger.debug('%s is expired in 1.3.0, use %s instead.' % (value, v))
value = v
return super(Message, self).__getitem__(value)
def get(self, v, d=None):
try:
return self[v]
except KeyError:
return d
def __str__(self):
return '{%s}' % ', '.join(
['%s: %s' % (repr(k),repr(v)) for k,v in self.items()])
Expand Down
98 changes: 71 additions & 27 deletions itchat/storage/templates.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
import logging, copy, pickle
from weakref import ref

from ..returnvalues import ReturnValue
from ..utils import update_info_dict

logger = logging.getLogger('itchat')

class AttributeDict(dict):
def __getattr__(self, value):
keyName = value[0].upper() + value[1:]
try:
return self[keyName]
except KeyError:
raise AttributeError("'%s' object has no attribute '%s'" % (
self.__class__.__name__.split('.')[-1], value))
def get(self, v, d=None):
try:
return self[v]
except KeyError:
return d

class UnInitializedItchat(object):
def _raise_error(self, *args, **kwargs):
logger.warning('An itchat instance is called before initialized')
def __getattr__(self, value):
return self._raise_error

fakeItchat = UnInitializedItchat()

class ContactList(list):
''' when a dict is append, init function will be called to format that dict
'''
''' when a dict is append, init function will be called to format that dict '''
def __init__(self, *args, **kwargs):
super(ContactList, self).__init__(*args, **kwargs)
self.__setstate__(None)
@property
def core(self):
return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
@core.setter
def core(self, value):
self._core = ref(value)
def set_default_value(self, initFunction=None, contactClass=None):
if hasattr(initFunction, '__call__'):
self.contactInitFn = initFunction
Expand All @@ -28,7 +46,7 @@ def append(self, value):
contact = self.contactClass(value)
contact.core = self.core
if self.contactInitFn is not None:
contact = self.contactInitFn(contact) or contact
contact = self.contactInitFn(self, contact) or contact
super(ContactList, self).append(contact)
def __deepcopy__(self, memo):
r = self.__class__([copy.deepcopy(v) for v in self])
Expand All @@ -41,19 +59,21 @@ def __getstate__(self):
def __setstate__(self, state):
self.contactInitFn = None
self.contactClass = User
self.core = fakeItchat
def __str__(self):
return '[%s]' % ', '.join([repr(v) for v in self])
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__.split('.')[-1],
self.__str__())

fakeContactList = ContactList

class AbstractUserDict(dict):
class AbstractUserDict(AttributeDict):
def __init__(self, *args, **kwargs):
super(AbstractUserDict, self).__init__(*args, **kwargs)
self.__setstate__(None)
@property
def core(self):
return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
@core.setter
def core(self, value):
self._core = ref(value)
def update(self):
return ReturnValue({'BaseResponse': {
'Ret': -1006,
Expand Down Expand Up @@ -104,9 +124,6 @@ def search_member(self, name=None, userName=None, remarkName=None, nickName=None
'Ret': -1006,
'ErrMsg': '%s do not have members' % \
self.__class__.__name__, }, })
def __getattr__(self, value):
value = value[0].upper() + value[1:]
return self.get(value, '')
def __deepcopy__(self, memo):
r = self.__class__()
for k, v in self.items():
Expand All @@ -122,7 +139,7 @@ def __repr__(self):
def __getstate__(self):
return 1
def __setstate__(self, state):
self.core = fakeItchat
pass

class User(AbstractUserDict):
def __init__(self, *args, **kwargs):
Expand All @@ -146,32 +163,39 @@ def __deepcopy__(self, memo):
def __setstate__(self, state):
super(User, self).__setstate__(state)
self.verifyDict = {}
self.memberList = fakeContactList
self['MemberList'] = fakeContactList

class MassivePlatform(AbstractUserDict):
def __init__(self, *args, **kwargs):
super(MassivePlatform, self).__init__(*args, **kwargs)
self.__setstate__(None)
def __setstate__(self, state):
super(MassivePlatform, self).__setstate__(state)
self.memberList = fakeContactList
self['MemberList'] = fakeContactList

class Chatroom(AbstractUserDict):
def __init__(self, *args, **kwargs):
super(Chatroom, self).__init__(*args, **kwargs)
memberList = ContactList()
def init_fn(d):
d.chatroom = self
userName = self.get('UserName', '')
refSelf = ref(self)
def init_fn(parentList, d):
d.chatroom = refSelf() or \
parentList.core.search_chatrooms(userName=userName)
memberList.set_default_value(init_fn, ChatroomMember)
if 'MemberList' in self:
if not isinstance(self.memberList, ContactList):
for member in self.memberList:
memberList.append(member)
self['MemberList'] = memberList
else:
for member in self.memberList:
memberList.append(member)
self['MemberList'] = memberList
self['MemberList'] = memberList
@property
def core(self):
return getattr(self, '_core', lambda: fakeItchat)() or fakeItchat
@core.setter
def core(self, value):
self._core = ref(value)
self.memberList.core = value
for member in self.memberList:
member.core = value
def update(self, detailedMember=False):
r = self.core.update_chatroom(self.userName, detailedMember)
if r:
Expand Down Expand Up @@ -218,11 +242,29 @@ def search_member(self, name=None, userName=None, remarkName=None, nickName=None
return copy.deepcopy(friendList)
else:
return copy.deepcopy(contact)
def __setstate__(self, state):
super(Chatroom, self).__setstate__(state)
if not 'MemberList' in self:
self['MemberList'] = fakeContactList

class ChatroomMember(AbstractUserDict):
def __init__(self, *args, **kwargs):
super(AbstractUserDict, self).__init__(*args, **kwargs)
self.__setstate__(None)
@property
def chatroom(self):
r = getattr(self, '_chatroom', lambda: fakeChatroom)()
if r is None:
userName = getattr(self, '_chatroomUserName', '')
r = self.core.search_chatrooms(userName=userName)
if isinstance(r, dict):
self.chatroom = r
return r or fakeChatroom
@chatroom.setter
def chatroom(self, value):
if isinstance(value, dict) and 'UserName' in value:
self._chatroom = ref(value)
self._chatroomUserName = value['UserName']
def get_head_image(self, imageDir=None):
return self.core.get_head_img(self.userName, self.chatroom.userName, picDir=imageDir)
def delete_member(self, userName):
Expand Down Expand Up @@ -263,9 +305,7 @@ def __deepcopy__(self, memo):
return r
def __setstate__(self, state):
super(ChatroomMember, self).__setstate__(state)
self.chatroom = self.fakeChatroom

ChatroomMember.fakeChatroom = Chatroom()
self['MemberList'] = fakeContactList

def wrap_user_dict(d):
userName = d.get('UserName')
Expand All @@ -276,3 +316,7 @@ def wrap_user_dict(d):
else:
r = MassivePlatform(d)
return r

fakeItchat = UnInitializedItchat()
fakeContactList = ContactList()
fakeChatroom = Chatroom()

0 comments on commit 559063a

Please sign in to comment.