From a Python script I want to create a RAR file. I will need to communicate with Rar.exe because I only want the first RAR volume from a multi-volume archive set, nothing more. The -vp switch makes sure Create next volume ? [Y]es, [N]o, [A]ll is asked after each volume. The first time this question pops up, I want to answer No. How do I accomplish this?
I've been reading and trying a lot of things and I found out something like this can be accomplished with pexpect. I've been trying the two different Windows ports: wexpect and winpexpect. The result is that my script will hang. No RAR file is created. This is my code:
import wexpect
import sys
rarexe = "C:\Program Files\WinRAR\Rar.exe"
args = ['a', '-vp', '-v2000000b', 'only_first.rar', 'a_big_file.ext']
child = wexpect.spawn(rarexe, args)
child.logfile = sys.stdout
index = child.expect(["Create next volume ? [Y]es, [N]o, [A]ll",
wexpect.EOF, wexpect.TIMEOUT], timeout=10)
if index == 0:
child.sendline("N")
else:
print('error')
Other approaches are welcome too.
I had the same issue, because there are several (buggy) version of wexpect on the web.
Check out of my variant, which is a copy of an instance, which worked for me.
This can be installed using
pip install wexpect
The answer to my problem has two parts.
As betontalpfa indicated, I must use his version of wexpect. It can be installed easily:
pip install wexpect
The expect_exact documentation of Pexpect explains that it uses plain string matching instead of compiled regular expressions patterns in the list. This means the parameters must be properly escaped or the expect_exact method must be used instead of expect. It gave me this working code:
import wexpect
import sys
rarexe = "C:\Program Files\WinRAR\Rar.exe"
args = ['a', '-vp', '-v2000000b', 'only_first.rar', 'a_big_file.ext']
child = wexpect.spawn(rarexe, args)
# child.logfile = sys.stdout
rar_prompts = [
"Create next volume \? \[Y\]es, \[N\]o, \[A\]ll",
"\[Y\]es, \[N\]o, \[A\]ll, n\[E\]ver, \[R\]ename, \[Q\]uit",
wexpect.EOF, wexpect.TIMEOUT]
index = child.expect(rar_prompts, timeout=8)
while index < 2:
# print(child.before)
if index == 0:
print("No next volume")
child.sendline("N")
elif index == 1:
print("Overwriting existing volume")
child.sendline("Y")
index = child.expect(rar_prompts, timeout=8)
else:
print('Index: %d' % index)
if index == 2:
print("Success!")
else:
print("Time out!")
And the output gives:
Overwriting existing volume
No next volume
Index: 2
Success!
Related
I am trying to get a list of all the branches available on my repository using Python with this code :
import subprocess
branches = ["All"]
command = "git branch -r"
branch_list = subprocess.check_output(command)
for branch in branch_list:
print branch
branches.append[branch]
What I want is to have something like :
print branches[0] # is "All"
print branches[1] # is "branch1"
print branches[2] # is "branch2"
etc etc
but instead of that I have
print branches[0] # is "All"
print branches[1] # is "b"
print branches[2] # is "r"
print branches[3] # is "a"
print branches[4] # is "n"
print branches[5] # is "c"
print branches[6] # is "h"
etc etc
Thank you for your time and your help
Taking a peek at the check_output documentation, it looks like we're getting a blob of bytes back. To make it easier to work with, we can decode it. Then, since git branch -r outputs one branch per line, split the string on newlines:
branches = subprocess.check_output(command).decode().split('\n')
BUT I think there's an even easier way to do it. Every single object in git corresponds to some file under the .git directory. In this case, you can find your list of branches in .git/refs/heads:
import os
branches = os.listdir('.git/refs/heads')
EDIT (2020/10/13): I've spent some more time with subprocess since writing this response and wanted to point out the text option (via subprocess.run):
If encoding or errors are specified, or text is true, file objects for stdin, stdout and stderr are opened in text mode using the specified encoding and errors or the io.TextIOWrapper default.
This means you could write the check_output expression as:
branches = subprocess.check_output(command, text=True).split('\n')
leaving encoding and decoding to the system. Whichever you prefer!
Try decodeing it:
stdout = subprocess.check_output('git branch -a'.split())
out = stdout.decode()
branches = [b.strip('* ') for b in out.splitlines()]
print(branches)
output:
['master', 'second', 'test']
For python3,
import subprocess
# refs/remotes for remote tracking branches.
# refs/heads for local branches if necessary, and
# refs/tags for tags
cmd = 'git for-each-ref refs/remotes --format="%(refname)"'
status, output = subprocess.getstatusoutput(cmd)
branches = ["All"]
if status == 0:
branches += output.split('\n')
print(branches)
For python2, replace subprocess with commands.
In Python I'm using pdfminer to read the text from a pdf with the code below this message. I now get an error message saying:
File "/usr/local/lib/python2.7/dist-packages/pdfminer/pdfpage.py", line 124, in get_pages
raise PDFTextExtractionNotAllowed('Text extraction is not allowed: %r' % fp)
PDFTextExtractionNotAllowed: Text extraction is not allowed: <cStringIO.StringO object at 0x7f79137a1
ab0>
When I open this pdf with Acrobat Pro it turns out it is secured (or "read protected"). From this link however, I read that there's a multitude of services which can disable this read-protection easily (for example pdfunlock.com. When diving into the source of pdfminer, I see that the error above is generated on these lines.
if check_extractable and not doc.is_extractable:
raise PDFTextExtractionNotAllowed('Text extraction is not allowed: %r' % fp)
Since there's a multitude of services which can disable this read-protection within a second, I presume it is really easy to do. It seems that .is_extractable is a simple attribute of the doc, but I don't think it is as simple as changing .is_extractable to True..
Does anybody know how I can disable the read protection on a pdf using Python? All tips are welcome!
================================================
Below you will find the code with which I currently extract the text from non-read protected.
def getTextFromPDF(rawFile):
resourceManager = PDFResourceManager(caching=True)
outfp = StringIO()
device = TextConverter(resourceManager, outfp, codec='utf-8', laparams=LAParams(), imagewriter=None)
interpreter = PDFPageInterpreter(resourceManager, device)
fileData = StringIO()
fileData.write(rawFile)
for page in PDFPage.get_pages(fileData, set(), maxpages=0, caching=True, check_extractable=True):
interpreter.process_page(page)
fileData.close()
device.close()
result = outfp.getvalue()
outfp.close()
return result
I had some issues trying to get qpdf to behave in my program. I found a useful library, pikepdf, that is based on qpdf and automatically converts pdfs to be extractable.
The code to use this is pretty straightforward:
import pikepdf
pdf = pikepdf.open('unextractable.pdf')
pdf.save('extractable.pdf')
As far as I know, in most cases the full content of the PDF is actually encrypted, using the password as the encryption key, and so simply setting .is_extractable to True isn't going to help you.
Per this thread:
Does a library exist to remove passwords from PDFs programmatically?
I would recommend removing the read-protection with a command-line tool such as qpdf (easily installable, e.g. on Ubuntu use apt-get install qpdf if you don't have it already):
qpdf --password=PASSWORD --decrypt SECURED.pdf UNSECURED.pdf
Then open the unlocked file with pdfminer and do your stuff.
For a pure-Python solution, you can try using PyPDF2 and its .decrypt() method, but it doesn't work with all types of encryption, so really, you're better off just using qpdf - see:
https://github.com/mstamy2/PyPDF2/issues/53
I used below code using pikepdf and able to overwrite.
import pikepdf
pdf = pikepdf.open('filepath', allow_overwriting_input=True)
pdf.save('filepath')
In my case there was no password, but simply setting check_extractable=False circumvented the PDFTextExtractionNotAllowed exception for a problematic file (that opened fine in other viewers).
Full disclosure, I am one of the maintainers of pdfminer.six. It is a community-maintained version of pdfminer for python 3.
This issue was fixed in 2020 by disabling the check_extractable by default. It now shows a warning instead of raising an error.
Similar question and answer here.
The 'check_extractable=True' argument is by design.
Some PDFs explicitly disallow to extract text, and PDFMiner follows the directive. You can override it (giving check_extractable=False), but do it at your own risk.
If you want to unlock all pdf files in a folder without renaming them, you may use this code:
import glob, os, pikepdf
p = os.getcwd()
for file in glob.glob('*.pdf'):
file_path = os.path.join(p, file).replace('\\','/')
init_pdf = pikepdf.open(file_path)
new_pdf = pikepdf.new()
new_pdf.pages.extend(init_pdf.pages)
new_pdf.save(str(file))
In pikepdf library it is impossible to overwrite the existing file by saving it with the same name. In contrast, you would like to copy the pages to the newly created empty pdf file, and save it.
I too faced the same problem of parsing the secured pdf but it has got resolved using pikepdf library. I tried this library on my jupyter notebbok and on windows os but it gave errors but it worked smoothly on Ubuntu
If you've forgotten the password to your PDF, below is a generic script which tries a LOT of password combinations on the same PDF. It uses pikepdf, but you can update the function check_password to use something else.
Usage example:
I used this when I had forgotten a password on a bank PDF. I knew that my bank always encrypts these kind of PDFs with the same password-structure:
Total length = 8
First 4 characters = an uppercase letter.
Last 4 characters = a number.
I call script as follows:
check_passwords(
pdf_file_path='/Users/my_name/Downloads/XXXXXXXX.pdf',
combination=[
ALPHABET_UPPERCASE,
ALPHABET_UPPERCASE,
ALPHABET_UPPERCASE,
ALPHABET_UPPERCASE,
NUMBER,
NUMBER,
NUMBER,
NUMBER,
]
)
Password-checking script:
(Requires Python3.8, with libraries numpy and pikepdf)
from typing import *
from itertools import product
import time, pikepdf, math, numpy as np
from pikepdf import PasswordError
ALPHABET_UPPERCASE: Sequence[str] = tuple('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
ALPHABET_LOWERCASE: Sequence[str] = tuple('abcdefghijklmnopqrstuvwxyz')
NUMBER: Sequence[str] = tuple('0123456789')
def as_list(l):
if isinstance(l, (list, tuple, set, np.ndarray)):
l = list(l)
else:
l = [l]
return l
def human_readable_numbers(n, decimals: int = 0):
n = round(n)
if n < 1000:
return str(n)
names = ['', 'thousand', 'million', 'billion', 'trillion', 'quadrillion']
n = float(n)
idx = max(0,min(len(names)-1,
int(math.floor(0 if n == 0 else math.log10(abs(n))/3))))
return f'{n/10**(3*idx):.{decimals}f} {names[idx]}'
def check_password(pdf_file_path: str, password: str) -> bool:
## You can modify this function to use something other than pike pdf.
## This function should throw return True on success, and False on password-failure.
try:
pikepdf.open(pdf_file_path, password=password)
return True
except PasswordError:
return False
def check_passwords(pdf_file_path, combination, log_freq: int = int(1e4)):
combination = [tuple(as_list(c)) for c in combination]
print(f'Trying all combinations:')
for i, c in enumerate(combination):
print(f"{i}) {c}")
num_passwords: int = np.product([len(x) for x in combination])
passwords = product(*combination)
success: bool | str = False
count: int = 0
start: float = time.perf_counter()
for password in passwords:
password = ''.join(password)
if check_password(pdf_file_path, password=password):
success = password
print(f'SUCCESS with password "{password}"')
break
count += 1
if count % int(log_freq) == 0:
now = time.perf_counter()
print(f'Tried {human_readable_numbers(count)} ({100*count/num_passwords:.1f}%) of {human_readable_numbers(num_passwords)} passwords in {(now-start):.3f} seconds ({human_readable_numbers(count/(now-start))} passwords/sec). Latest password tried: "{password}"')
end: float = time.perf_counter()
msg: str = f'Tried {count} passwords in {1000*(end-start):.3f}ms ({count/(end-start):.3f} passwords/sec). '
msg += f"Correct password: {success}" if success is not False else f"All {num_passwords} passwords failed."
print(msg)
Comments
Obviously, don't use this to break into PDFs which are not your own. I hold no responsibility over how you use this script or any consequences of using it.
A lot of optimizations can be made.
Right now check_password uses pikepdf, which loads the file from disk for every "check". This is really slow, ideally it should run against an in-memory copy. I haven't figured out a way to do that, though.
You can probably speed this up a LOT by calling qpdf directly using C++, which is much better than Python for this kind of stuff.
I would avoid multi-processing here, since we're calling the same qpdf binary (which is normally a system-wide installation), which might become the bottleneck.
At work I can select multiple .xlsx files, and right clicking on one file will give me the option of combining the files to make a .pdf. Now I want to use the same functionality in one of my scripts. That is, selecting multiple files and send the paths of these files as arguments to a Python script.
I've spent soon an hour searching for solutions, but I haven't found any good answers. It seems there are some C# answers, but I don't know how to convert the code to Python. Is it even possible to achieve it at all?
Edit - Sample script:
import sys, os
for file in sys.argv:
print(file)
os.system("PAUSE")
I know this is a "bit" late to post an answer here, but I had tried Olav's solution some months ago and it didn't work completely: the working directory was the script's working directory, so I had to delete the if condition for it to work, but it selected all the files in all Windows Explorer windows (which I wanted too, so it worked partially for me). But after coming back to this, I thought on this idea. I don't know if this answer worked for anyone else, but for me it didn't completely so I thought I could improve it and post my solution here.
This code is a mix of this answer by James Kent: https://stackoverflow.com/a/43892579/8228163 (corrected by me to work at least under Windows 7) and Olav's answer and the result worked for me - the script detects the files only in the current Windows Explorer window. I think all of this works from Vista (not sure, running 7 here) to 10, but I'm not completely sure. The other answer was made to work with XP. When I started this script on Windows 10, I think it worked, but I don't have 10 anymore so I don't know for sure (I'm using 7 again, so for 7 this works).
import win32gui, time
from win32con import PAGE_READWRITE, MEM_COMMIT, MEM_RESERVE, MEM_RELEASE, PROCESS_ALL_ACCESS, WM_GETTEXTLENGTH, WM_GETTEXT
from commctrl import LVS_OWNERDATA, LVM_GETITEMCOUNT, LVM_GETNEXTITEM, LVNI_SELECTED
import os
import struct
import ctypes
import win32api
import datetime
import win32com.client as win32
import win32ui
import psutil
import subprocess
import time
import urllib.parse
clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' #Valid for IE as well!
def getEditText(hwnd):
# api returns 16 bit characters so buffer needs 1 more char for null and twice the num of chars
buf_size = (win32gui.SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0) +1 ) * 2
target_buff = ctypes.create_string_buffer(buf_size)
win32gui.SendMessage(hwnd, WM_GETTEXT, buf_size, ctypes.addressof(target_buff))
return target_buff.raw.decode('utf16')[:-1]# remove the null char on the end
def _normaliseText(controlText):
'''Remove '&' characters, and lower case.
Useful for matching control text.'''
return controlText.lower().replace('&', '')
def _windowEnumerationHandler(hwnd, resultList):
'''Pass to win32gui.EnumWindows() to generate list of window handle,
window text, window class tuples.'''
resultList.append((hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd)))
def searchChildWindows(currentHwnd,
wantedText=None,
wantedClass=None,
selectionFunction=None):
results = []
childWindows = []
try:
win32gui.EnumChildWindows(currentHwnd,
_windowEnumerationHandler,
childWindows)
except win32gui.error:
# This seems to mean that the control *cannot* have child windows,
# i.e. not a container.
return
for childHwnd, windowText, windowClass in childWindows:
descendentMatchingHwnds = searchChildWindows(childHwnd)
if descendentMatchingHwnds:
results += descendentMatchingHwnds
if wantedText and \
not _normaliseText(wantedText) in _normaliseText(windowText):
continue
if wantedClass and \
not windowClass == wantedClass:
continue
if selectionFunction and \
not selectionFunction(childHwnd):
continue
results.append(childHwnd)
return results
def explorer_fileselection():
global clsid
address_1=""
files = []
shellwindows = win32.Dispatch(clsid)
w=win32gui
window = w.GetForegroundWindow()
#print("window: %s" % window)
if (window != 0):
if (w.GetClassName(window) == 'CabinetWClass'): # the main explorer window
#print("class: %s" % w.GetClassName(window))
#print("text: %s " %w.GetWindowText(window))
children = list(set(searchChildWindows(window)))
addr_edit = None
file_view = None
for child in children:
if (w.GetClassName(child) == 'WorkerW'): # the address bar
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'ReBarWindow32'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'Address Band Root'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'msctls_progress32'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'Breadcrumb Parent'):
addr_edit = addr_child
addr_children = list(set(searchChildWindows(child)))
for addr_child in addr_children:
if (w.GetClassName(addr_child) == 'ToolbarWindow32'):
text=getEditText(addr_child)
if "\\" in text:
address_1=getEditText(addr_child)[text.index(" ")+1:]
print("Address --> "+address_1)
for window in range(shellwindows.Count):
window_URL = urllib.parse.unquote(shellwindows[window].LocationURL,encoding='ISO 8859-1')
window_dir = window_URL.split("///")[1].replace("/", "\\")
print("Directory --> "+window_dir)
if window_dir==address_1:
selected_files = shellwindows[window].Document.SelectedItems()
for file in range(selected_files.Count):
files.append(selected_files.Item(file).Path)
print("Files --> "+str(files))
while True:
explorer_fileselection()
time.sleep(1)
This looks for the active Windows Explorer window, gets that window's address and then the address is used on Olav's answer for it to check if that address is equal to one of the addresses opened in Windows Explorer, getting the files from the active window. Btw, as this is script is a modified copy of both answers, it has their limitations:
Like it's on Olav's answer "Edit: Doesn't work yet, at least when using context menu", then this won't probably work either, as it's the same code - it's just the working directory which is different (though, I don't know what he meant with that, but from what I've tested, it worked).
And like it's on James Kent's answer, this doesn't work for desktop, only for opened windows using Windows Explorer.
The encoding='ISO 8859-1' is because I'm portuguese, but it can be changed, JUST make sure both directories are equal without %?s or that won't work!
Note: for Windows XP, see the the original answer (https://stackoverflow.com/a/43892579/8228163) and to get the files from all Windows Explorer windows, just remove the if condition from Olav's answer.
Thanks Olav and James Kent for the answers, because I would have taken MUCH more time trying to find out how to do this (I'm a Python/any language very begginner).
Hope this helps! Cheers!
Edit: Doesn't work yet, at least when using context menu
I found a partial solution here. However it doesn't work if Internet Explorer is open (how do I detect this?). Also, if multiple instances of Windows Explorer is open, the selected files in all windows are counted. I added a check for this.
import win32com.client as win32
import os
import win32ui
def explorer_fileselection():
working_dir = os.getcwd()
clsid = '{9BA05972-F6A8-11CF-A442-00A0C90A8F39}' #Valid for IE as well!
shellwindows = win32.Dispatch(clsid)
files = []
try:
for window in range(shellwindows.Count):
window_URL = shellwindows[window].LocationURL
window_dir = window_URL.split("///")[1].replace("/", "\\")
if window_dir == working_dir:
selected_files = shellwindows[window].Document.SelectedItems()
for file in range(selected_files.Count):
files.append(selected_files.Item(file).Path)
except: #Ugh, need a better way to handle this one
win32ui.MessageBox("Close IE!", "Error")
del shellwindows
return files
print(*explorer_fileselection(), sep="\n")
--- prints the selected files:
C:\Users\oe\Python\ssa\util\test3.docx
C:\Users\oe\Python\ssa\util\__init__.py
C:\Users\oe\Python\ssa\util\explorer_filer.py
C:\Users\oe\Python\ssa\util\test1.xlsx
C:\Users\oe\Python\ssa\util\test2.xls
I think I will add a *valid_ext parameter to the function, so I can do calls like explorer_fileselection("xlsx", "xls") to get Excel-files only.
This is really a Windows question and not very specific to Python.
You want the windows shell to show a menu item for your script in the shell context menu.
To accomplish this, you can add some keys to the registry. See Add menu item to windows context menu only for specific filetype for an explanation of how to add your menu item.
After that, when you select multiple files and send them to your script, you will see the files as command line arguments. If you select 10 files, the script will be ran 10 times.
Are you asking about how to get the list of files, or are you asking about how to do the conversion?
If you are asking about selecting files (which is what is sounds like to me), are you looking for a GUI solution or a command line solution?
you can show all the .xlsx files in a folder by using the os.listdir() function is the os library and then filtering them to just the files containing .xlsx like so:
files = [ fi for fi in os.listdir(folder) if fi.endswith(suffix) ]
you could then print the list of files with their indices next to them and ask the user to enter the indices of the files that they want to select like so:
for fInd,f in enumerate(files):
print '%s) %s' %(fInd, f)
response = raw_input('select files by indices (coma separated)')
keeperInds = response.split(',')
keeperInds = [int(keeperInd) for keeperInd in keeperInds]
# you should also check to make sure that the selected inds are valid...
selectedFiles = [files[ind] for ind in keeperInds]
that will give you a list of selected files that you can pass into your script.
If you actually need help with the conversion from the .xlsx files into a pdf you could have a look at this - you might be able to change it to save .pdfs by changing the file format.
Converting .XLSX to .XLS in Python with win32com.client module
I'm trying to make a script where python goes through a directory, finds all files that ends with *ref.SDAT, and then opens them all.
So far, I have the sorting of files process. The wanted files are put into reflist:
import os
import glob
import subprocess
os.chdir("/Users/BabyJ/Desktop/MRSDATA")
reflist = glob.glob('*raw_ref.SDAT')
print "These are the ref files:"
for i in reflist:
os.system('open+%s') %i
I don't know how to structure the syntax so that os.system will open all of the components of the list though.
The % operator wants the 'open+%s' string as its left-hand side. You are offering it the return value of os.system(). Also, I think you wanted a space, not a + in the string.
Try this:
os.system('open %s'%i)
I assuming judging from your use of open that you are on a Mac or Unix system. If that is the case use either of the following to get you up and running.
for i in reflist:
os.system('open ' + '%s' % i)
or:
for i in reflist:
subprocess.call('open ' + '%s' % i, shell = True)
Using subprocess is the better solution as os.system is, though not technically gone from the language, deprecated in Python per the official documentation.
Hope that helps.
EDIT:
If you're using windows sub in start for open.
Struggling with this for literally two weeks. I can't get this .zip to unpack. I know that it is correct because I can make it work in a standard command line and it in shows everything that I know is in it. Trying to unpack a zip and then rename and copy portions of that file to another folder. Here is the basic setup:
import subprocess
cmd = ['7z', 'e', 'site']
sp = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
After that import I try and unpack it using:
sp.communicate([cmd, 'r"C:\Users\boster\desktop\data1.zip"'])
now it gets past this point because it moves onto my if else section but it doesn't unpack it. I know that it will run the following because it gets to the end and returns my else statement and then prompts me to run the data again.
if "sz + business_date" == name:
shutil.copy(sz%s) % business_date
os.renames(sales.xls)
shutil.copy(sc%s) % business_date
os.renames(cosales.xls)
shutil.copy(aj%s) % business_date
os.renames(money.xls)
shutil.copy(cc%s) % business_date
os.renames(count.xls)
else:
print "Repoll %s for %s" % (item, business_date)
print "Once information is downloaded press enter."
re_download = raw_input(" ")
data_one()
I've left out some of the stuff like the business_date portions because it's returning that as a variable in the else so I know it's grabbing that information correctly. I just have no idea why this won't unpack. Please help. If this isn't sufficient I'll upload the whole module if you'd like.
I finally managed to get this to work. It wasn't unpacking on the subprocess.communicate and since call can't be used with PIPE I just dumped all the commands at the beggining and ended up with the following.
def extract_data_one():
for item in sites:
os.chdir(r"\\svr-dc\ftp site\%s\Daily" % item)
subprocess.call(['7z', 'e', 'data1.zip', '*.*'])
Thanks for all your help.
I encountered a similar problem when using 7zip compressed file with subprocess, I solved my problem by another way. This is my code,
def zip_files_in_special_path(rom_path, rom_name):
pre_cwd = os.getcwd()
os.chdir(rom_path)
cmd_str = r'C:\7-Zip\7z a -tzip -r '+rom_name+' *'
try:
status = os.system(cmd_str)
if status<=1:
return True
else:
raise RunCmdError('run 7z to zip files failed!')
finally:
os.chdir(pre_cwd)
hope to help you.