4

I've been scouring the internet for a solution and everything i've come across hasn't helped. So now i turn to you.

Traceback (most recent call last):
  File "cardreader.py", line 9, in <module>
    import ATRdb as ATR
  File "/home/pi/Desktop/CardReader/ATRdb.py", line 4, in <module>
    import cardreader
  File "/home/pi/Desktop/CardReader/cardreader.py", line 113, in <module>
    main()
  File "/home/pi/Desktop/CardReader/cardreader.py", line 40, in main
    getData(db)
  File "/home/pi/Desktop/CardReader/cardreader.py", line 98, in getData
    if ATR.checkPerms(db,track1):
AttributeError: 'module' object has no attribute 'checkPerms'

I have two files cardreader.py & ATRdb.py

---ATRdb.py has this setup

import sys
import MYSQLdb
import datetime
import cardreader

def checkPerms(db, securitycode):
    try:
       cursor = db.cursor()
       cursor.execute("""SELECT permissions FROM atrsecurity.employee WHERE securitycode = %s""", (securitycode))
       r = cursor.fetchone()
       Permissions = r
       if '3' in Permissions[0]:
          return True
       else:
          return False
     except Exception:
         cardreader.main()
         return False

---cardreader.py has this setup

import sys
import usb.core
import usb.util
import MYSQLdb
import ATRdb as ATR

def main():
    db = MYSQLdb.connect(HOST,USER, PASS, DB)
    print("Please swipe your card...")
    getData(db)
    main()
    db.close()
def getData(db):
    #
    #lots of code to get card data
    #
    if ATR.checkPerms(db, track1):
       print ("User has permission")
       unlockDoor()

i get the error at the "If ATR.checkPerms():" part. Any help would be appreciated (first python project)

8
  • 1
    Why does main have a call to itself? Particularly before you close the database connection? And are these the complete contents of the files? Commented Dec 19, 2013 at 20:13
  • 2
    Please post the full error and traceback instead of just describing it in English. There's a good chance it won't help here, but it might—and it's a good habit to get into, because there are a lot of problems where the traceback immediately gives the answer to a reader. Commented Dec 19, 2013 at 20:17
  • the recursion of main is because we want the cardreader.py to continually run...waiting for a card swipe. And no, there is more code that i didn't include, but simple functions like unlockDoor and some logging info Commented Dec 19, 2013 at 20:18
  • 1
    @MaylorTaylor: Recursion is not the right way to do that in Python; use a loop. Commented Dec 19, 2013 at 20:19
  • 1
    It's definitely a circular import issue. The traceback makes it clear. Might be fixable with an if __name__ == '__main__' check. Commented Dec 19, 2013 at 20:21

1 Answer 1

8

Your problem is circular imports.

In cardreader, you do this:

import ATRdb as ATR

That starts importing ATRdb, but a few lines into the code, it hits this:

import cardreader

The exact sequence from here depends on whether cardreader.py is your main script or not, and on whether your top-level code that calls main is protected by an if __name__ == '__main__' guard (and assuming that top-level code is in cardreader rather than elsewhere). Rather than try to explain all the possibilities in detail (or wait for you to tell us which one matches your actual code), let's look at what we know is true based on the behavior:

In some way, you're calling main before finishing the import of ATRdb.

This means that, at this point, ATRdb has nothing in it but sys, MYSQLdb, and datetime (and a handful of special attributes that every module gets automatically). In particular, it hasn't gotten to the definition of checkPerms yet, so no such attribute exists in the module yet.

Of course eventually it's going to finish importing the rest of ATRdb, but at that point it's too late; you've already called main and it tried to call ATR.checkPerms and that failed.

While there are various complicated ways to make circular imports work (see the official FAQ for some), the easiest and cleanest solution is to just not do it. If ATRdb needs some functions that are in cardreader, you should probably factor those out into a third module, like cardutils, that both ATRdb and cardreader can import.

Sign up to request clarification or add additional context in comments.

11 Comments

In addition, note that even if the circular import problem wasn't there, your code would fail too because main() calls itself. Since importing cardreader runs main(), it would crash your program (maximum call stack depth exceeded).
While the issue is a circular import, the description of how the circular import causes the problem is wrong. cardreader.py is run as the main file. It imports ATRdb, which imports cardreader as a module (different from running it as the main file), which tries to import ATRdb again and doesn't because ATRdb is already being imported. The cardreader import then hits the main() call and starts running even though ATRdb isn't done importing. Note that the execution of the main file has yet to hit main(); this main() call shouldn't even be happening.
@MaxNoel: Note that it wouldn't crash until swiping 1000 cards, and it's plausible nobody intended it to run for that long. Whether that makes it acceptable, or a recipe for a nightmare bug nobody will notice until 6 months after all the original devs have quit, is hard to guess. :)
@user2357112: I was assuming that he's calling main from an if __name__ == '__main__' guard, in which case it can be simplified down to the two steps I described. But you're right, if he's just calling main directly, it can't be, and he might well be doing that. I'll edit the answer.
I think your understanding of circular imports might be a bit off. When A imports B and B imports A, the second import doesn't suspend the importing of B to finish up A. It loads A into the current namespace and then continues with no other effect. When importing B finishes, then execution returns to A.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.