[Python] How to set a persistent SQLite3 database?

Hello,

I’ve finally finished most of the development of my app, but I’m facing (i hope) one last problem: my python created database is never saved on the phone.


here you can see the database created by my other app SeaAiNetic in the .local/share folder. Bellow, the folder of my harbour-deepfish app is empty.

I added the QT += sql to my .pro file as mentioned here or here

and every time i make a change on my database i do con.commit() as it can be seen in my code here

I did not have this issue with my other app because i do not create the database with python but with QML instead.

So currently I can open the app and fill the database, but as soon as i close and then re-open the app, it’s like a new fresh installation. (perfect feature for data protection)

On the other side, when using QML Live from the SDK i never face this issue.

I think I’m missing something on the building files but I don’t know what, since, when comparing to other apps using python, we have the same configs.

Thank you anyone for your help or tips on this ! (yes you can build the app and use my API key i set hardcoded for testing)

Fast and dirty solution would be to create it in qml and just use it in python?

multimodal, from @cypherpunks does, I believe, do it all in python

But I think he always creates the database by hand.

Do you have sailjail enabled?

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

[X-Sailjail]
ApplicationName=Deepfish
Permissions=Internet

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.

6 Likes

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:

[X-Sailjail]
Permissions=Internet;Location
OrganizationName=app.qml
ApplicationName=multimodal
4 Likes
con = sqlite3.connect(self.configuration_database)

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

2 Likes

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]);
      load_settings(settings);
    });

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.

2 Likes

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]);

2 Likes

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