سؤال

Using the same code in a doctest and in the shell yields different outputs.
I have a function called a() that runs through a few tests.
Those same tests are used in a doctest (test() ).
With a() I get OBJECT-BLANKLINE-OBJECT while the test() gives me an error and shows only the first OBJECT.
Is this a flaw in the doctest module?

Here's the whole file with both a() and test() in the top:

'''
>>> u1 = User("luis@fc.up.pt", "simples")
>>> u2 = User("ana@fc.up.pt", "complicada")
>>> u2.askFriend(u1)
>>> u1.recvRequest(u2)
>>> u1.confirmFriend(u2)
>>> p1 = Post(u1, "O ultimo post", "http://www.wikipedia.org")
>>> p2 = Post(u2, "A ultima resposta", "http://www.google.com")
>>> c = Comments()
>>> c.add(p1)
>>> c.add(p2)
>>> f1 = c.search(user="ana@fc.up.pt")
>>> print(f1)
A ultima resposta
http://www.google.com
0 Gosto, 0 Nao gosto
>>> f2 = c.search(likes=1)
>>> print(f2)
<BLANKLINE>
>>> f3 = c.search(text='post')
>>> print(f3)
O ultimo post
http://www.wikipedia.org
0 Gosto, 0 Nao gosto
<BLANKLINE>
A ultima resposta
http://www.google.com
0 Gosto, 0 Nao gosto
'''

def test():
    import doctest
    doctest.testmod()

def a():
    u1 = User("luis@fc.up.pt", "simples")
    u2 = User("ana@fc.up.pt", "complicada")
    u2.askFriend(u1)
    u1.recvRequest(u2)
    u1.confirmFriend(u2)
    p1 = Post(u1, "O ultimo post", "http://www.wikipedia.org")
    p2 = Post(u2, "A ultima resposta", "http://www.google.com")
    c = Comments()
    c.add(p1)
    c.add(p2)
    f3 = c.search(text="post")
    print(f3)

import string

class User:

    def __init__(self,email,passwd):
        self.email = email
        self.passwd = passwd
        self.name = None
        self.year = None
        self.active = True
        self.recv = [] 
        self.conf = []
        self.setPassword(self.passwd)

    def __str__(self):
        if self.name == None and self.active == True:
            return str(self.email) + ':' + 'ativa'

        elif self.name != None and self.active == True:
            return str(self.name) + ':' + str(self.email) + ':' + 'ativa'

        elif self.name != None and self.active == False:
            return str(self.name) + ':' + str(self.email) + ':' + 'inativa'

        else:
            return str(self.email) + ':' + 'inativa'

    def getEmail(self):
        return self.email

    def setPassword(self,passwd):
        abc = string.ascii_lowercase
        cifra = abc[3:] + abc[:3]
        dec = list(passwd)
        passwdCif = ""
        for i in dec:
            cif = cifra[abc.find(i)]
            passwdCif += cif
        self.passwd = passwdCif

    def getPassword(self):
        return self.passwd

    def setName(self,name):
        self.name = name

    def getName(self):
        return self.name

    def setBirth(self,year,month,day):
        self.year = year
        self.month = month
        self.day = day

    def getBirth(self):
        if self.year == None:
            return None
        else:
            return '(' + str(self.year) + ', ' + str(self.month) + ', ' + str(self.day) + ')'

    def isActive(self):
        if self.active == True:
            return True
        else:
            return False

    def setActive(self):
        self.active = True

    def setInactive(self):
        self.active = False

    def askFriend(self,u):
        self.conf.append(u)

    def recvRequest(self,u):
        self.recv.append(u)

    def confirmFriend(self,u):
        if len(self.recv) == 0:
            return None
        else:
            for i in self.recv:
                if i == u:
                    self.recv.remove(i)
                    self.conf.append(i)
                else:
                    return None


    def isFriend(self,u):
        if u in self.conf:
            return True
        elif self == u:
            return True
        else:
            return False

    def showPending(self):
        if len(self.recv) == 0:
            return None
        else:
            for i in self.recv:
                print i

    def showFriends(self):
        if len(self.conf) == 0:
            return None
        else:
            for i in self.conf:
                print i

class Post():
    def __init__(self,u,text='',link=None):
        self.u = u
        self.text = text
        self.link = link
        self.seg = None
        self.ant = None
        self.likeList = []
        self.dislikeList = []

    def __str__(self):
        if self.link == None:
            return str(self.text) + '\n' + str(len(self.likeList)) + ' Gosto, ' + str(len(self.dislikeList)) + ' Nao gosto'
        else:
            return str(self.text) + '\n' + str(self.link) + '\n' + str(len(self.likeList)) + ' Gosto, ' + str(len(self.dislikeList)) + ' Nao gosto'

    def updateText(self,text):
        self.text = text

    def updateLink(self,link):
        self.link = link

    def like(self,u):
        if (u in self.u.conf) or (u == self.u):
            if u in self.dislikeList:
                self.dislikeList.remove(u)
                self.likeList.append(u)
            elif u in self.likeList:
                return None
            else:
                self.likeList.append(u)
        else:
            return None

    def dislike(self,u):
        if (u in self.u.conf) or (u == self.u):
            if u in self.likeList:
                self.likeList.remove(u)
                self.dislikeList.append(u)
            elif u in self.dislikeList:
                return None
            else:
                self.dislikeList.append(u)
        else:
            return None

class Comments():
    def __init__(self, u=None, text='', link=None):
        self.u = u
        self.text = text
        self.link = link
        self.topo = None
        self.fim = None

    def __str__(self):
        actual = self.topo
        s = ''
        if actual == None:
            return ''
        while actual != None:
            if actual.seg == None:
                s += str(actual)
                actual = actual.seg
            elif actual.seg != None:
                s += str(actual) + '\n' + '\n'
                actual = actual.seg
        return s

    def add(self,comment):
        if self.topo == None:
            comment.ant = None
            comment.seg = None
            self.topo = comment
            self.fim = comment
        else:
            comment.ant = None
            comment.seg = self.topo
            self.topo.ant = comment
            self.topo = comment

    def remove(self,comment):
        actual = self.topo
        if (self.topo == self.fim) and (self.topo == comment):
            self.topo = None
            self.fim = None
            actual = None
        while actual!=None:
            if actual == comment:
                if actual.ant == None:
                    self.topo = actual.seg
                    actual.seg.ant = None
                elif actual.seg == None:
                    self.fim = actual.ant
                    actual.ant.seg = None
                else:
                    actual.seg.ant = actual.ant
                    actual.ant.seg = actual.seg
                break
            else:
                actual = actual.seg

    def countLike(self):
        count = 0
        actual = self.topo
        while actual != None:
            if len(actual.likeList) >= 1:
                count += 1
                actual = actual.seg
            else:
                actual = actual.seg
        return count

    def showRecentComments(self,n):
        count = 1
        actual = self.topo
        sC = ''
        if actual == None:
            return None
        while actual != None:
            if count < n:
                if actual.seg == None:
                    sC += str(actual)
                    count += 1
                    actual = actual.seg
                else:
                    sC += str(actual) + '\n' + '\n'
                    count += 1
                    actual = actual.seg
            elif count == n:
                sC += str(actual)
                count += 1
                actual = actual.seg
            elif count > n:
                break 
        print sC

    def search(self, user=None, likes=None, dislikes=None, text=None):
        result = []
        actual = self.topo
        cR = Comments()
        if actual == None:
            return None

        while actual != None:
            if user != None:
                if actual.u.email != user:
                    actual = actual.seg
                elif actual.u.email == user:
                    result.append(actual)
                    actual = actual.seg
            elif user == None:
                break
        actual = self.topo

        while actual != None:
            if likes != None:
                if likes > len(actual.likeList):
                    actual = actual.seg
                elif likes <= len(actual.likeList):
                    if actual in result:
                        actual = actual.seg
                    else:
                        result.append(actual)
                        actual = actual.seg
            elif likes == None:
                break
        actual = self.topo

        while actual != None:
            if dislikes != None:
                if dislikes > len(actual.dislikeList):
                    actual = actual.seg
                elif dislikes <= len(actual.dislikeList):
                    if actual in result:
                        actual = actual.seg
                    else:
                        result.append(actual)
                        actual = actual.seg
            elif dislikes == None:
                break
        actual = self.topo

        while actual != None:
            if text != None:
                if text not in actual.text:
                    actual = actual.seg
                elif text in actual.text:
                    if actual in result:
                        actual = actual.seg
                    else:
                        result.append(actual)
                        actual = actual.seg
            elif text == None:
                break
        if len(result) != 0:
            for i in result:
                cR.add(i)
        return cR

And here's the output I get using both a() and test():

>>> a()
O ultimo post
http://www.wikipedia.org
0 Gosto, 0 Nao gosto

A ultima resposta
http://www.google.com
0 Gosto, 0 Nao gosto
>>> test()
**********************************************************************
File "__main__", line 22, in __main__
Failed example:
    print(f3)
Expected:
    O ultimo post
    http://www.wikipedia.org
    0 Gosto, 0 Nao gosto
    <BLANKLINE>
    A ultima resposta
    http://www.google.com
    0 Gosto, 0 Nao gosto
Got:
    A ultima resposta
    http://www.google.com
    0 Gosto, 0 Nao gosto
**********************************************************************
1 items had failures:
   1 of  16 in __main__
***Test Failed*** 1 failures.
>>> 

I'd also like to apologize for my previous badly asked question.
Hopefully this one will help me and others.

هل كانت مفيدة؟

المحلول

There is one obvious difference between your doctest and your function: While your function a does this:

# previous code
c.add(p2)
f3 = c.search(text="post")
print(f3)

your doctest does this:

# previous code
c.add(p2)
f1 = c.search(user="ana@fc.up.pt")
print(f1)
f2 = c.search(likes=1)
print(f2)
f3 = c.search(text='post')
print(f3)

I do not know what exactly happens there, but probably you should write your function to do the same thing. If the result still is different, there is something wrong with doctest, otherwise with your code.

edit:

Now i start to understand why you are trouble, and it is deeeeeeep trouble. It starts with this line right on top of your search function:

actual = self.topo

I think you are not aware of the way Python assigns properties. Later in your code you change actual, and then assign self.topo to actual again:

actual.seg = "somevalue" # sorry, i can't remember what you did"
actual = self.topo

That second line is completely meaningless, as actual already is self.topo! It is not the value of self.topo but it is self.topo.

Instead of writing

actual.seg = "somevalue"

you could just write

self.topo.seg = "somevalue"

Both lines do exactly the same. So while you thought you were altering some independent property actual you really changed self.topo all the time. And that means that actual is not equal at each start of the function, but always has the value it had at the last run of c.search.

I have just seen that you are doing this in some of the other functions as well, which means you are altering the state of your Comments instance c every time you call such a function. That, of course, results in different output for each test.

To make this more understandable, here is an example with a list:

>>> a_list = ['one','two','three']
>>> b_list = a_list
>>> b_list.pop()
'three'
>>> a_list
['one', 'two']

As you see: Allthoug i did pop the element from b_list, it is gone from a_list as well. This is because the statement b_list = a_list means literally that b_list is now the same as a_list.

Hope this helps.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top