3

I am trying to put together a script to convert multiple (>50) Tab files into shapefiles. I am planning on executing this through the python console in QGIS 3.8.1

When I run the below code all I get is the print returns to the console, it does not copy over (or spit errors).

I think the answer lies in the OPTIONS section of the parameters dictionary, but for the life of me I cannot find documentation on the appropriate syntax.

from qgis import processing
from os import listdir

def convert_layer(layer, save_location):
    print("Converting", layer, "to Shapefile...")
    inLayer = inPath + "\\" + layer
    print(inLayer)
    outLayer = save_location +"\\"+ layer[:-4] + '.shp'
    print(outLayer)
    
    # print(output)
    processing.run('gdal:convertformat', {'INPUT':inLayer, 'OPTIONS':"", 'OUTPUT':outLayer})

inPath = "folder a"
outPath = "folder b"

tabList = list(filter(lambda x: x.endswith('.tab'), os.listdir(inPath)))

for tabFile in tabList:
    convert_layer(tabFile, outPath)

1 Answer 1

3

Try the script below. Just change the in_folder and out_folder variables to match your own file paths. The in_folder is the path to the folder where your .tab files are stored and out_folder is the path to the folder in which you want to save the new shapefiles. I tested this in the Python console in QGIS 3.16 and it worked perfectly with my own file paths.

# path to folder where your .tab files are located
in_folder = 'C:\\Users\\Ben\\Desktop\\GIS Files\\Vector Data\\Global Map_Mi_data'

# path to folder where you want to save your shapefiles
out_folder = 'C:\\Users\\Ben\\Desktop\\GIS Files\\Vector Data\\Global Map_Mi_data\\Shapefiles'

def convert_layer(in_layer, save_location):
    out_layer = os.path.join(save_location, f'{in_layer.name.replace(".tab", ".shp")}')
    processing.run("gdal:convertformat",
                    {'INPUT': in_layer.path,
                    'OPTIONS':'',
                    'OUTPUT':out_layer})

src_dir = os.scandir(in_folder)
for file in src_dir:
    if file.name.endswith('.tab'):
        convert_layer(file, out_folder)

However, given that you have a fairly large number of files to convert, I would recommend considering wrapping the operation in a QgsTask which will run in a background thread, meaning your gui will remain responsive while the task is carried out.

Below is a more sophisticated version of the script above which shows how to do this. In this script I have also used the QFileDialog class to get the paths to the source and destination folders to make the things a little more versatile and user friendly.

class RunAlg(QgsTask):
    alg_finished = pyqtSignal(str)
    def __init__(self, desc, in_folder, out_folder):
        self.desc = desc
        QgsTask.__init__(self, self.desc, QgsTask.CanCancel)
        
        self.in_folder = in_folder
        self.out_folder = out_folder
        
        self.src_dir = os.scandir(self.in_folder)
        self.tab_list = [file for file in self.src_dir if file.name.endswith('.tab')]
        
    def run(self):
        if not self.tab_list:
            return False
        for count, item in enumerate(self.tab_list):
            out_layer = os.path.join(self.out_folder, f'{item.name.replace(".tab", ".shp")}')
            if self.isCanceled():
                return False
            processing.run("gdal:convertformat",
                        {'INPUT': item.path,
                        'OPTIONS':'',
                        'OUTPUT':out_layer})
            self.alg_finished.emit(f'{count+1}/{len(self.tab_list)}')
        return True
 
    def finished(self, result):
        iface.messageBar().clearWidgets()
        if result:
            iface.messageBar().pushMessage(f'{len(self.tab_list)} files successfully converted')
        else:
            iface.messageBar().pushMessage('Task failed/cancelled')
        
class Main():
    def __init__(self, in_path, out_path):
        self.in_path = in_path
        self.out_path = out_path
        self.msg = iface.messageBar().createMessage('Converting files...')
        self.prog_lbl = QLabel()
        self.prog = QProgressBar(self.msg)
        self.kill = QPushButton('Cancel', self.msg)
        self.kill.clicked.connect(self.cancel_pushed)
        self.msg.layout().addWidget(self.prog_lbl)
        self.msg.layout().addWidget(self.prog)
        self.msg.layout().addWidget(self.kill)
        self.task1 = RunAlg('Running: convert format', self.in_path, self.out_path)
        self.task1.begun.connect(lambda: iface.messageBar().pushWidget(self.msg))
        self.task1.alg_finished.connect(self.update_progress)

    def update_progress(self, prog):
        self.prog_lbl.setText(prog)
        current = int(prog.split('/')[0])
        total = int(prog.split('/')[1])
        pcnt = (current/total*100)
        self.prog.setValue(pcnt)
        
    def start_task(self):
        QgsApplication.taskManager().addTask(self.task1)
                
    def cancel_pushed(self):
        self.task1.cancel()
        iface.messageBar().clearWidgets()


src_path = QFileDialog().getExistingDirectory(iface.mainWindow(), 'Select input folder')
if src_path:
    save_path = QFileDialog().getExistingDirectory(iface.mainWindow(), 'Select save folder')
    if save_path:

        T = Main(src_path, save_path)
        T.start_task()

Example result after running the above code in the qgis Python console is shown below:

enter image description here

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.