0

I have written a Python program to take the backup of all objects of MySQL db individually. The program works fine when run on my machine, but when I use cx_freeze to create an executable file, it fails to run on the other machine. I found the cause of the error to be the text file for configuration. When I don't write a configuration file, the program runs fine, else it gives an error.

My code for extraction: mysql_extractor.py. Please have a look at the filter_parsing function, the probable source of error.

[mysql_extractor.py]

#!/usr/bin/env python3

"""
__title__        = "mysql_extractor.py"
__description__  = "Script to extract objects of MySQL database individually"

"""

from __future__ import print_function
import argparse
import os
import sys
import pymysql
import encodings.idna

class MySQLExtractor:

############################################
#
#    PUBLIC METHODS
#
############################################

   directory = ""
   dumpcmd   = ""

   def parse_argument(self):
      self.parser = argparse.ArgumentParser(description="MySQL dump process")
      args_conn = self.parser.add_argument_group(title="Database Connection")
      args_conn.add_argument('--host', dest="hostname", default="127.0.0.1", help="Host name or IP Address")
      args_conn.add_argument('-u', '--username', dest="username", default="root", help="Database user name.")
      args_conn.add_argument('--password', dest="password", default="", help="Password for the given user.")
      args_conn.add_argument('-d', '--db', dest="db", default="test", help="Database name to connect to.")

      args_filter = self.parser.add_argument_group(title="Filters", description="All object names given in any filter MUST be fully schema qualified.")
      args_filter.add_argument('--gettables', dest="gettables", action="store_true", help="Get all tables only")

      self.args = self.parser.parse_args()
   # end _parse_arguments()

   def gettables(self):
      try:
         print ("Dumping Tables..")
         conn = pymysql.connect(host=self.args.hostname, user=self.args.username, passwd=self.args.password, database=self.args.db)
         cursor = conn.cursor()
         if not os.path.exists("tables"):
            os.makedirs("tables")
            os.chdir("tables")
            query = "show full tables where Table_Type != 'VIEW'"
            cursor.execute(query)
            for row in cursor:
               dumpcmd = self.dumpcmd
               dumpcmd +=  " " + row[0] + " --no-data > " + row[0] + ".sql"
               os.system(dumpcmd)
            os.chdir(self.directory)
         cursor.close()
         conn.close()
      except pymysql.Error as e:
         print("Error lin connecting to the DB: " + str(e) )
         sys.exit(2)
   # end gettables

   def filter_parsing(self):
      """
      Some more code here, but not relevant to the question
      """
      self.directory = self.args.db
      os.makedirs(self.directory)
      os.chdir(self.directory)

      # Create config file <Probable source of error>
      filename = "my_config"
      f = open(filename, 'w')
      f.write("[mysqldump]\n")
      f.write("host='"+ self.args.hostname + "'\n")
      f.write("user='"+ self.args.username + "'\n")
      f.write("password='"+ self.args.password + "'\n")
      f.close()

      self.directory = os.getcwd()
      self.dumpcmd = "mysqldump --defaults-file=" + self.directory + "/my_config" +" --skip-dump-date " + self.args.db

      # If the following command is used and config file is not created, it gives no error.
      # self.dumpcmd = "mysqldump -u " + self.args.username + " -h " + self.args.hostname + " --password=" + self.args.password + "  --skip-dump-date " + self.args.db 

      #gettables is selected
      if self.args.gettables==True:
         self.gettables()
         return
   # end filter_parsing

#end class MySQLExtractor


p = MySQLExtractor()
p.parse_argument()
try:
   p.filter_parsing()
finally:
   print ("Done")      

This code works fine when run on my machine. But when I create an executable file and run it on other machine, it gives error(s). Here is my setup.py file

[setup.py]

import sys
from cx_Freeze import setup, Executable
# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {"packages": ["os","MySQLdb"], "excludes": ["tkinter"]}

# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
    base = "Win32GUI"

setup(  name = "extractor",
        version = "0.1",
        description = "My GUI application!",
        options = {"build_exe": build_exe_options},
        executables = [Executable("mysql_extractor.py", base=base)])

The error thrown is:

Traceback (most recent call last):
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1161, in _load_backward_compatible
  File "/usr/lib64/python3.4/site-packages/cx_Freeze-5.0-py3.4-linux-x86_64.egg/cx_Freeze/initscripts/__startup__.py", line 12, in <module>
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1161, in _load_backward_compatible
  File "/usr/lib64/python3.4/site-packages/cx_Freeze-5.0-py3.4-linux-x86_64.egg/cx_Freeze/initscripts/Console.py", line 21, in <module>
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1191, in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1161, in _load_backward_compatible
  File "/home/AD/abhishek.bhola/Documents/tmp/tmp_test.py", line 97, in <module>
  File "/home/AD/abhishek.bhola/Documents/tmp/tmp_test.py", line 74, in filter_parsing
  File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
  File "<frozen importlib._bootstrap>", line 2222, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 2164, in _find_spec
  File "<frozen importlib._bootstrap>", line 1940, in find_spec
  File "<frozen importlib._bootstrap>", line 1916, in _get_spec
  File "<frozen importlib._bootstrap>", line 1897, in _legacy_get_spec
  File "<frozen importlib._bootstrap>", line 863, in spec_from_loader
  File "<frozen importlib._bootstrap>", line 904, in spec_from_file_location
OSError: zipimport: can not open file ./lib64/python34.zip
Abhishek B
  • 37
  • 11

1 Answers1

0

This problem has been detected and is already solved in the source repository. The problem is the os.chdir() call that is made when using relative paths to start up the executable. You have three choices for now:

  • use an absolute path for starting the executable
  • get the updated source and build it (then you can use relative paths)
  • wait for the next release of cx_Freeze to be made (hopefully soon!)
Anthony Tuininga
  • 6,388
  • 2
  • 14
  • 23
  • While I'll try with the absolute path, I could work on another alternative. I'm not sure about the reason why it worked. So I created a temp text file before changing directory in the parent folder and then later delete the same file at the end. This solved the problem without using the absolute path. But thanks for the solution. – Abhishek B Dec 02 '16 at 00:43
  • The next release of cx_Freeze (5.0.1) was made today with this issue resolved. – Anthony Tuininga Jan 08 '17 at 04:04