[Python] How to set a persistent SQLite3 database?

Do you have sailjail enabled?

yes, if you check my .desktop file you can see that:


the harbout-multimodal creates the database at : ROUTE_FILE = '/usr/share/harbour-multimodal/route.db

I tried doing the same but with my app name instead and got a unable to open database file error.

Doing it with QML :
Component.onCompleted: LocalStorage.openDatabaseSync(“language.db”, “1.0”,“Open AI DB”, 1000000)

does not change the problem because i thing the python database is created somewhere else temporarily

Test again with disabling sailjail

same issue

but using the QML to create the database did create a .sqlite file on my phone, it just wasn’t populated by the python scripts

Podqast creates the db from python but has a similar issue when sailjail is enabled, maybe you can learn something from there…

That code is way over complicated for me today. I don’t even see where the database is created in the peewee.py file.

So this did solve the problem ! But i had to use a different path:

ROUTE_FILE = ".local/share/harbour-deepfish/Deepfish/language.db"

I’m pretty sure that’s not the best way to do it…but it works !

1 Like

So it seems you are affected by sailjail. Remember that removing the entry is not the same as disabling. You have to do that explicitely.

Also, it seems you have not set an org name.

1 Like

I did not understand how the org name works, I saw some repositories with it but what’s the proper way to do it ?

change the Group: Qt/Qt in the .yaml file by org.jojo ?

the sailjail part will be fun to look at on the last step of the dev ideas i have: to make the app add entries to the vocabulary app…

No. You set the OrganizationName in the [X-Sailjail] section of the .desktop file. And you also set the ApplicationName there. Then you can create your database in .local/share/orgname/appname/. The Group definition in .yaml has nothing to do with it. Actually, it has nothing to do with anything and you should just remove it.


This is a read-only database that is provided (along with the qml and py files) inside the rpm package and contains the station data, etc.

All other databases are created in Python (configuration.py)

self.configuration_directory = os.environ['XDG_CONFIG_HOME'] + "/app.qml/multimodal/"
self.configuration_database = self.configuration_directory + "settings.db"
con = sqlite3.connect(self.configuration_database)

Organization and application names are set in QML like that (harbour-multimodal.qml):

  Component.onCompleted: {
    Qt.application.name = 'multimodal'
    Qt.application.organization = 'app.qml'

And in the desktop file:

con = sqlite3.connect(self.configuration_database)

Either opens an existing database or creates a new database file if it doesn’t exist.


thank you very much for this explanation !

Unfortunately I don’t know how to adapt my python.calls from pyotherside, to “call” for functions inside a class, since the call function only takes functions.

Currently I call for each function inside the languagedownloader.py file whenever needed. But in your approach you use the MultiModalConfiguration class. If i understand correctly, your init_ function is there to handle the different system files throughout each OS. And then you call the self inside each other function so they know where the self.configuration_database is.

How could I have the same approach in my case ? For example, I set the same init_ function, set all my python code inside a class, some_var = MyClass(), but then how do I call for the functions from the qml files ?

I first create the class in configuration.py:

class MultiModalConfiguration:
  def __init__(self):
   self.configuration_directory = os.environ['XDG_CONFIG_HOME'] + "/app.qml/multimodal/"

 def load(self, program_version):   
   self.program_version = program_version
   con = sqlite3.connect(self.configuration_database)

The constructor method __init__ is there to set up the various instance variables like e.g. self.configuration_directory etc.

At the end of the Python file, the instance is created:
multimodal_configuration = MultiModalConfiguration()

In the QML file PythonHandler.qml the instance is then imported from the python file into QML:

    importModule('configuration', function () {
      const settings = call_sync('configuration.multimodal_configuration.load', [app.version]);

And then call_sync executes the load() method from instance multimodal_configuration inside module configuration passing app.version as a single parameter.
Because it’s call_sync the call waits until the execution of the Python code is finished and saves the return values into settings but it would work the same with call just that there would be no blocking and thus no direct return value would be passed from Python to QML.


Just to clarify before a possible confusion arises:

the call_sync does not have to be inside the importModule callback code block.
It’s just there to make sure load() is not executed prematurely.

There are plenty of calls to methods outside this block, e.g.

call('configuration.multimodal_configuration.save', [app.settings]);


Thank you very much for the explanation. I tried to do it but I’m missing something because it’s not working. I will find a solution to implement it in the future.

I made some slight changes ¹ and it seems to be working fine :slight_smile:

I can send you the files I’ve altered if you tell me how.

¹ To the version available on openrepos

1 Like

you can do a git push if you want to, or mail/telegram them to me if you prefer, thank you again for the work !

I’ve sent you a link to the archive as DM
It should only contain files I’ve altered using the currently available version from OpenRepos as basis.