3

I am making a utility program which has multiple programs built into it but I made some changes to my program for it re-run when the user has prompted which then for some reason, I am facing the error

import * only allowed at module level

Here's my code

def main():
    
    import os
    import sys
    import time
    import pywhatkit as whatsapp
    from speedtest import Speedtest
    from tkinter import *
    from tkinter import messagebox
    from os import listdir
    from PIL import Image

    print("*"*30)
    print("Utility Build v1: Starting")
    print("*"*30)

    time.sleep(3)

    print("NOTE: Before using this program for repairing corrupted disk, please locate this utility .py file into the corrupted storage. Thanks")

    time.sleep(3)

    print("*"*30)
    print("*"*30)
    print("Commands: Choose by inputting allocated number")

    print("Utility 1: Speed Test")
    print("Utility 2: Whatsapp Message Automation")
    time.sleep(2)
    print("Please Wait...Loading")
    time.sleep(4)
    print("Utility 3: Disk/Removable Storage Repair(a.k.a Dr Corrupt)")
    print("Utility 4: Python .py status monitor")

    print("*"*30)
    print("*"*30)
    print("q = Quit Utility Program")

    input_ = input(": ")

    if input_ == "q":
        exit()
       
    if input_ == "1":

        time.sleep(2)

        print("*"*30)
        print("Speed Test: Starting")
        print("*"*30)
        
        st = Speedtest()

        Download_ = print("Your connection download speed is:", st.download())
        Upload_ = print("Your connection upload speed is:", st.upload())
        Download1_ = st.download()
        Upload1_ = st.upload()

        print("*"*30)
        print("Speed Test: Finishing Up!")
        print("*"*30)

        answer = input("Would you like results? ")

        if answer == "yes":
            print("NOTE: The first 2 digits frm the left is your internet speed")
            time.sleep(2)
            top = Tk()
            top.geometry("100x100")
            messagebox.showinfo("Speed Test: Download", Download1_)
            top.mainloop()

            reply = input("Would like to leave Utility Build(yes) or go to home page?(no) ")

        else:
            reply1 = print("Would like to leave Utility Build(yes) or go to home page?(no) ")
            if reply1 == "yes":
                main()
            else:
                exit()

    if input_ == "2":
        whatsapp.sendwhatmsg("+61450776320", "Hi, this is a test", 0, 0)

    if input_ == "3":
        
        for filename in listdir('./'):
          if filename.endswith('.png'):
            try:
              img = Image.open('./'+filename) # open the image file
              img.verify() # verify that it is, in fact an image
            except (IOError, SyntaxError) as e:
              print('Bad file:', filename) # print out the names of corrupt files
vvvvv
  • 25,404
  • 19
  • 49
  • 81
DevangSahani
  • 57
  • 1
  • 8
  • don't do `import *`, all it does it clutter up your namespace. – Z4-tier Aug 26 '20 at 12:40
  • 1
    Move the imports outside the function, like the error message is cryptically telling you to. I have to admit, this one's a bit hard to understand if you don't know what it means already, though it's clear enough when you do. – Mad Physicist Aug 26 '20 at 12:41
  • I assume you understand what "import *" means, since your code contains it. I assume you know what "only allowed" means. Is "at module level" confusing? – Karl Knechtel Aug 26 '20 at 12:43
  • By any chance can you show me what your trying to say. I understand a little bit but would like to confirm. thanks – DevangSahani Aug 26 '20 at 12:44
  • I moved the imports out of the functions but it seems to boot the program but not run anything. – DevangSahani Aug 26 '20 at 12:54
  • 2
    Unlike Java and others, Python Code doesn't automatically run the main function. Outside of the function, just call `main()` or write `if __name__ == '__main__': main()` – Dustin Aug 26 '20 at 12:58

1 Answers1

8

"Module level" just means in a part of the script that's not in a class or function. Any names you define there go directly into the module namespace.

The error message is therefore just saying to move

def main():
    
    import os
    import sys
    import time
    import pywhatkit as whatsapp
    from speedtest import Speedtest
    from tkinter import *
    from tkinter import messagebox
    from os import listdir
    from PIL import Image

to

import os
import sys
import time
import pywhatkit as whatsapp
from speedtest import Speedtest
from tkinter import *
from tkinter import messagebox
from os import listdir
from PIL import Image

def main():

Actually, the interpreter only really cares about the line from tkinter import *. The others are a matter of convention and readability.

CPython does optimizations on the local namespace inside a function that requires the interpreter to know the names of all local variables up-front. A star import prevents that from happening since you don't know what names will be in the imported module until you run it. The global namespace doesn't have this restriction, so you can do star imports there.

Python is a language for consenting adults. Just because something is "bad practice" or not maintainable does not make it a syntax error.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • Yes, I tried doing the solution you have presented but for some reason it runs the program and ends it. – DevangSahani Aug 26 '20 at 13:08
  • 2
    @DevangSahani. That's because you never call the function you wrote. A `def` statement creates a function object, nothing more. Add `main()` to the bottom of your script, optionally inside an import guard like `if __name__ == '__main__':` so that the function only gets run when you execute the module as a script, but not when you import it into another. – Mad Physicist Aug 26 '20 at 13:09
  • Sorry, I don't understand what you mean by 'I never called the function'. incredibly sorry to bug you so much right now but trying to show me what you meant in the code will be helpful – DevangSahani Aug 26 '20 at 13:12
  • @DevangSahani. Read my updated comment. I spelled it out for you since I know that the first few steps are hard. – Mad Physicist Aug 26 '20 at 13:15
  • 1
    @DevangSahani. Dustin has given you the same advice. The key is that the name `main` has no special meaning in python. It's a useful convention at best. – Mad Physicist Aug 26 '20 at 13:18