Skip to content
Snippets Groups Projects
utils.py 39.1 KiB
Newer Older
    RC_SUFFIX =  resourceSuffix
    assert os.path.exists(pathUi), '*.ui file does not exist: {}'.format(pathUi)

    if pathUi not in FORM_CLASSES.keys():
        #parse *.ui xml and replace *.h by qgis.gui
        doc = QDomDocument()

        #remove new-lines. this prevents uic.loadUiType(buffer, resource_suffix=RC_SUFFIX)
        #to mess up the *.ui xml
        f = open(pathUi, 'r')
        txt = ''.join(f.readlines())
        f.close()
        doc.setContent(txt)

        # Replace *.h file references in <customwidget> with <class>Qgs...</class>, e.g.
        #       <header>qgscolorbutton.h</header>
        # by    <header>qgis.gui</header>
        # this is require to compile QgsWidgets on-the-fly
        elem = doc.elementsByTagName('customwidget')
        for child in [elem.item(i) for i in range(elem.count())]:
            child = child.toElement()
            className = str(child.firstChildElement('class').firstChild().nodeValue())
            if className.startswith('Qgs'):
                cHeader = child.firstChildElement('header').firstChild()
                cHeader.setNodeValue('qgis.gui')

        #collect resource file locations
        elem = doc.elementsByTagName('include')
        qrcPathes = []
        for child in [elem.item(i) for i in range(elem.count())]:
            path = child.attributes().item(0).nodeValue()
            if path.endswith('.qrc'):
                qrcPathes.append(path)



        buffer = io.StringIO()  # buffer to store modified XML
        buffer.write(doc.toString())
        buffer.flush()
        buffer.seek(0)


        #make resource file directories available to the python path (sys.path)
        baseDir = os.path.dirname(pathUi)
        tmpDirs = []
        for qrcPath in qrcPathes:
            d = os.path.dirname(os.path.join(baseDir, os.path.dirname(qrcPath)))
            if d not in sys.path:
                tmpDirs.append(d)
        sys.path.extend(tmpDirs)

        #load form class
        try:
            FORM_CLASS, _ = uic.loadUiType(buffer, resource_suffix=RC_SUFFIX)
        except SyntaxError as ex:
            FORM_CLASS, _ = uic.loadUiType(pathUi, resource_suffix=RC_SUFFIX)
        buffer.close()
        FORM_CLASSES[pathUi] = FORM_CLASS

        #remove temporary added directories from python path
        for d in tmpDirs:
            sys.path.remove(d)

    return FORM_CLASSES[pathUi]

def zipdir(pathDir, pathZip):
    """
    :param pathDir: directory to compress
    :param pathZip: path to new zipfile
    """
    #thx to https://stackoverflow.com/questions/1855095/how-to-create-a-zip-archive-of-a-directory
    """
    import zipfile
    assert os.path.isdir(pathDir)
    zipf = zipfile.ZipFile(pathZip, 'w', zipfile.ZIP_DEFLATED)
    for root, dirs, files in os.walk(pathDir):
        for file in files:
            zipf.write(os.path.join(root, file))
    zipf.close()
    """
    import zipfile
    relroot = os.path.abspath(os.path.join(pathDir, os.pardir))
    with zipfile.ZipFile(pathZip, "w", zipfile.ZIP_DEFLATED) as zip:
        for root, dirs, files in os.walk(pathDir):
            # add directory (needed for empty dirs)
            zip.write(root, os.path.relpath(root, relroot))
            for file in files:
                filename = os.path.join(root, file)
                if os.path.isfile(filename):  # regular files only
                    arcname = os.path.join(os.path.relpath(root, relroot), file)
                    zip.write(filename, arcname)

def initQgisApplication(pythonPlugins=None, PATH_QGIS=None, qgisDebug=False, qgisResourceDir=None):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    """
    Initializes the QGIS Environment
    :return: QgsApplication instance of local QGIS installation
    """
    if pythonPlugins is None:
        pythonPlugins = []
    assert isinstance(pythonPlugins, list)

    if os.path.exists(os.path.join(DIR_REPO, 'qgisresources')):
        qgisResourceDir = os.path.join(DIR_REPO, 'qgisresources')
    if isinstance(qgisResourceDir, str):
        assert os.path.isdir(qgisResourceDir)
        import importlib, re
        modules = [m for m in os.listdir(qgisResourceDir) if re.search(r'[^_].*\.py', m)]
        modules = [m[0:-3] for m in modules]
        for m in modules:
            mod = importlib.import_module('qgisresources.{}'.format(m))
            if "qInitResources" in dir(mod):
                mod.qInitResources()
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    envVar = os.environ.get('QGIS_PLUGINPATH', None)
    if isinstance(envVar, list):
        pythonPlugins.extend(re.split('[;:]', envVar))
Benjamin Jakimow's avatar
Benjamin Jakimow committed

    # make plugin paths available to QGIS and Python
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    os.environ['QGIS_PLUGINPATH'] = ';'.join(pythonPlugins)
    os.environ['QGIS_DEBUG'] = '1' if qgisDebug else '0'
    for p in pythonPlugins:
        sys.path.append(p)

    if isinstance(QgsApplication.instance(), QgsApplication):
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        return QgsApplication.instance()
Benjamin Jakimow's avatar
Benjamin Jakimow committed
    else:

        if PATH_QGIS is None:
            # find QGIS Path
            if sys.platform == 'darwin':
                # search for the QGIS.app
Benjamin Jakimow's avatar
Benjamin Jakimow committed
                import qgis, re
                assert '.app' in qgis.__file__, 'Can not locate path of QGIS.app'
                PATH_QGIS_APP = re.split(r'\.app[\/]', qgis.__file__)[0] + '.app'
                PATH_QGIS = os.path.join(PATH_QGIS_APP, *['Contents', 'MacOS'])
Benjamin Jakimow's avatar
Benjamin Jakimow committed

                if not 'GDAL_DATA' in os.environ.keys():
                    os.environ['GDAL_DATA'] = r'/Library/Frameworks/GDAL.framework/Versions/Current/Resources/gdal'
Benjamin Jakimow's avatar
Benjamin Jakimow committed

                QApplication.addLibraryPath(os.path.join(PATH_QGIS_APP, *['Contents', 'PlugIns']))
                QApplication.addLibraryPath(os.path.join(PATH_QGIS_APP, *['Contents', 'PlugIns', 'qgis']))
Benjamin Jakimow's avatar
Benjamin Jakimow committed


            else:
                # assume OSGeo4W startup
                PATH_QGIS = os.environ['QGIS_PREFIX_PATH']

        assert os.path.exists(PATH_QGIS)

        qgsApp = QgsApplication([], True)
        qgsApp.setPrefixPath(PATH_QGIS, True)
        qgsApp.initQgis()
        def printQgisLog(msg, tag, level):
            if tag not in ['Processing']:
                if tag in ['Python warning', 'warning']:
                    import re
                    if re.search('(Deprecation|Import)Warning', msg) is not None:
                        return
                    else:
                        return
                print(msg)

        QgsApplication.instance().messageLog().messageReceived.connect(printQgisLog)

        #initiate a PythonRunner instance if None exists
        if not QgsPythonRunner.isValid():
            r = PythonRunnerImpl()
            QgsPythonRunner.setInstance(r)
Benjamin Jakimow's avatar
Benjamin Jakimow committed
        return qgsApp

class PythonRunnerImpl(QgsPythonRunner):
    """
    A Qgs PythonRunner implementation
    """

    def __init__(self):
        super(PythonRunnerImpl, self).__init__()


    def evalCommand(self, cmd:str, result:str):
        try:
            o = compile(cmd)
        except Exception as ex:
            result = str(ex)
            return False
        return True

    def runCommand(self, command, messageOnError=''):
        try:
            o = compile(command, 'fakemodule', 'exec')
            exec(o)
        except Exception as ex:
            messageOnError = str(ex)
            command = ['{}:{}'.format(i+1, l) for i,l in enumerate(command.splitlines())]
            print('\n'.join(command), file=sys.stderr)
            raise ex
            return False
        return True


def createCRSTransform(src, dst):
    assert isinstance(src, QgsCoordinateReferenceSystem)
    assert isinstance(dst, QgsCoordinateReferenceSystem)
    t = QgsCoordinateTransform()
    t.setSourceCrs(src)
    t.setDestinationCrs(dst)
    return t

if __name__ == '__main__':
    #nice predecessors
    qgsApp = initQgisApplication()
    assert nicePredecessor(26) == 25
    assert nicePredecessor(25) == 25
    assert nicePredecessor(23) == 20
    assert nicePredecessor(999) == 950
    assert nicePredecessor(1001) == 1000
    assert nicePredecessor(1.2) == 1.0      #
    assert nicePredecessor(0.8) == 0.5
    assert nicePredecessor(0.2) == 0.1
    assert nicePredecessor(0.021) == 0.01
    assert nicePredecessor(0.0009991) == 0.0005