First python script - autoimport in multiple decks

Hi altogether,

as just mentioned I am new to writing anki-scripts in python. Probably you can give me some hints where to search for information.
What I want to do:

  1. I have a list of usernames and passwords (think of some students)
    for every pair I want to do the following steps
  2. download/sync their ankiweb-profiles
  3. import a package (bunch of new cards)
  4. sync back

When I use Collection.sync_collection I get FULL_DOWNLOAD required, and if I use full_upload_or_download, I have to provide server_usn - which I don’t know what it is and I get the Error HttpError { code: 400, context: “missing original size”, source: None }

I think I missed to read some API-Documentation or I have to look at the code in a special way I do not know yet. I would appreciate any advice. Please don’t be angry if I missed something.

Thanks
Peter

Probably I should add my code - so you can probably see what I am missing

import os
from anki.collection import Collection 
from anki.collection import ImportAnkiPackageOptions, ImportAnkiPackageRequest

def apkg_import(col:Collection, filename):
    ''' importiert den filename in die Colection'''
    if os.path.isfile(filename):
        log = col.import_anki_package(
        ImportAnkiPackageRequest(
            package_path=filename,
            options=ImportAnkiPackageOptions(
                with_scheduling=False, with_deck_configs=False
            )
        ))
        print(log)
    else:
        print("Zu importierende Datei existiert nicht:", filename)

def load_from_server(col:Collection, username:str, password:str):
    auth = col.sync_login(username,password,None)
    print("auth:",auth)
    #col.save(trx=False)
    sync_output = col.sync_collection(auth,True)
    print("sync_output\n",sync_output)
    #col.full_upload_or_download(auth=auth,server_usn=None,upload=True)
    #print("download_output\n",download_output)
    return auth

def main():
    # Anki-Backend erstellen
    col = Collection("/tmp/Benutzer 1/collection.anki2")
    print(col.sched.deck_due_tree())

    #download
    auth = load_from_server(col,"username","passwd")

    # apkg_import(col,"/tmp/existiertnicht.apkg") #Nur zum Testen
    apkg_import(col,"/tmp/test_export.apkg")

    #und wieder rauf
    #sync_output = col.sync_collection(auth, False)
    #print("sync_out2:\n",sync_output)
    col.full_upload_or_download(auth=auth,server_usn=None,upload=True)

if __name__ == "__main__":
    main()

On Running I get:

sync_output
 host_number: 4
required: FULL_SYNC
new_endpoint: "https://sync4.ankiweb.net/"

blocked main thread for 237ms:
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
    cli.main()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
    run()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 284, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
    exec(code, run_globals)
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 54, in <module>
    main()
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 42, in main
    apkg_import(col,"/tmp/test_export.apkg")
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 10, in apkg_import
    log = col.import_anki_package(
  File "/home/peter/.local/lib/python3.10/site-packages/anki/collection.py", line 362, in import_anki_package
    log = self._backend.import_anki_package_raw(request.SerializeToString())
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend_generated.py", line 1865, in import_anki_package_raw
    return self._run_command(35, 2, message)
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend.py", line 169, in _run_command
    print("".join(traceback.format_stack()))

changes {
}
log {
  duplicate {
    id {
      nid: 1428574092310
    }
    fields: "{{c1::1}}cm2 = {{c2::100}}mm2"
    fields: ""
  }
  duplicate {
    id {
      nid: 1428574154944
    }
    fields: "{{c1::1}} {{c3::km2}} = {{c2::1 000 000}} m2"
    fields: ""
  }
  duplicate {
    id {
      nid: 1428574246056
    }
    fields: "Nenne alle Flächeneinheiten in absteigender Reihenfolge"
    fields: "km², ha, a, m², dm², cm², mm² "
  }
  duplicate {
    id {
      nid: 1428574284232
    }
    fields: "Um bei Flächeneinheiten in die {{c1::nächstkleinere}} Einheit zu gelangen, mus"
    fields: "Oder das Komma um zwei Stellen nach rechts verschoben werden:12,456 m² = 1245,6"
  }
  duplicate {
    id {
      nid: 1428574333847
    }
    fields: "Um bei Flächeneinheiten in die {{c2::nächstgrößere}} Einheit umzurechnen mus"
    fields: "Oder das Komma um zwei Stellen nach links verschoben werden:12m² = 0,12 a"
  }
  found_notes: 5
}

blocked main thread for 773ms:
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
    cli.main()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
    run()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 284, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
    exec(code, run_globals)
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 54, in <module>
    main()
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 47, in main
    col.full_upload_or_download(auth=auth,server_usn=None,upload=True)
  File "/home/peter/.local/lib/python3.10/site-packages/anki/collection.py", line 1097, in full_upload_or_download
    self._backend.full_upload_or_download(
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend_generated.py", line 113, in full_upload_or_download
    raw_bytes = self._run_command(1, 6, message.SerializeToString())
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend.py", line 169, in _run_command
    print("".join(traceback.format_stack()))

Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/__main__.py", line 39, in <module>
    cli.main()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 430, in main
    run()
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/adapter/../../debugpy/launcher/../../debugpy/../debugpy/server/cli.py", line 284, in run_file
    runpy.run_path(target, run_name="__main__")
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 321, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 135, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/home/peter/.vscode/extensions/ms-python.debugpy-2024.6.0-linux-x64/bundled/libs/debugpy/_vendored/pydevd/_pydevd_bundle/pydevd_runpy.py", line 124, in _run_code
    exec(code, run_globals)
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 54, in <module>
    main()
  File "/home/peter/skripte/python/anki/anki_autoimport.py", line 47, in main
    col.full_upload_or_download(auth=auth,server_usn=None,upload=True)
  File "/home/peter/.local/lib/python3.10/site-packages/anki/collection.py", line 1097, in full_upload_or_download
    self._backend.full_upload_or_download(
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend_generated.py", line 113, in full_upload_or_download
    raw_bytes = self._run_command(1, 6, message.SerializeToString())
  File "/home/peter/.local/lib/python3.10/site-packages/anki/_backend.py", line 173, in _run_command
    raise backend_exception_to_pylib(err)
anki.errors.SyncError: HttpError { code: 400, context: "missing original size", source: None }

Please don’t do that. It puts an undue strain on AnkiWeb, and could get you automatically blocked for too many authentications. You’ll either need to get your students to import the decks themselves, or investigate other solutions like AnkiHub or AnkiCollab.

Hey Damien, thanks for the reply.
AnkiCollab is great. I currently start to use that. Works for all those students having AndroidMobiles to manage their decks or PCs at home. I won’t use this way for many students, let’s say less than 10 - they can’t collaborate on AnkiCollab.
Actually I have to add all the cards manually. What amount of students would lead to an undue strain? If so, could I use it with my own ankiweb server for these students?

Beside all these thoughts - could you explain, what I miss (probably I haven’t read an important document) and how to get a better understanding of the error and the API?

AnkiWeb’s usage terms do not allow such access. If you set up your own sync server, it will be fine though, since you won’t be impacting resources shared by others. You may find it also fixes the error you’re getting.

1 Like

Hi Damien,

that works fine. Full-Download with the self-hosted server works finde. Am I right, I don’t have a chance to get the web-interface running on this self-hosted server?

Regards Peter

Yes, I’m afraid the sync server is only for syncing.