Giter VIP home page Giter VIP logo

apy's Introduction

apy

Anki is a flash card program which makes remembering things easy. apy is a Python script for easily adding cards to Anki. It does not require Anki to be running at the same time.

Important

  • This script and its author(s) are not affiliated/associated with the main Anki project in any way.
  • Use this software entirely at your own risk. Frequent backups are encouraged.

Table of Contents

Install instructions

apy can be installed in the "usual" way with pip:

pip install apyanki

However, note that installing Python packages outside virtual environments is not recommended, even at the user level! If you do this, then be aware that you may experience issues due to conflicts with other packages/tools installed in the same manner.

Instead, the best way to install apy for normal usage is with pipx. This will ensure apy doesn't interfere with other Python packages already on your system.

If you don't already have pipx, install it with your distribution's package manager. For instance, on Ubuntu:

sudo apt update
sudo apt install pipx

Then, install apy with:

pipx install apyanki

Requirements

apy should work for Python 3.9 and later.

Technically, apy does not depend on any existing Anki installation, since it pulls in a copy of the non-GUI components of Anki as a separate dependency. However, you still need to have an Anki database with collections and profile settings already existing on your machine, since apy can't create one from nothing.

Usage

apy --help

Some examples:

# Add card with interactive editor session
apy add

# Add single card with specified preset (see configuration for more info on
# presets)
apy add-single -s preset "Question/Front" "Answer/Back"

# List leech cards (will show cid values for each card). Note that the query
# should be similar to a search query in the Anki browser.
apy list -v tag:leech

# Review and possibly edit file with given cid
apy review cid:12345678

apy can be combined with editor specific configuration and workflows to improve the process of adding and editing cards. For more information about this, see the Wiki.

Configuration

apy loads configuration from ~/.config/apy/apy.json. The following keys are currently recognized:

  • base_path: Specify where apy should look for your Anki database. This is usually something like /home/your_name/.local/share/Anki2/.
  • img_viewers: Specify a dictionary of image viewer commands. Each key is a file extension. The value is a command list, e.g. ['display', 'density', '300'] which specifies the command and its options to use for the corresponding key (file extension).
  • img_viewers_default: Specify the default command to show an image. Must be provided as a list of the command and desired options, such as ['feh', '-d'].
  • markdown_models: Specify a list of models for which apy will use a markdown converter.
  • markdown_pygments_style: Specify the code highlight scheme to use for fenced code blocks in Markdown notes. See the Pygments documentation for more details.
  • pngCommands/svgCommands: Set LaTeX commands to generate PNG/SVG files. This is inspired by the Edit LaTeX build process addon to Anki.
  • presets: Specify preset combination of model and tags for use with apy add-single.
  • profile_name: Specify which profile to load by default.
  • query: Specify default query for apy list, apy review and apy tag.
  • review_show_cards: Whether to show list of cards by default during note review

An example configuration:

{
  "base_path": "/home/your_name/.local/share/Anki2/",
  "profile_name": "MyAnkiProfile",
  "query": "tag:leech",
  "presets": {
    "default": { "model": "Custom", "tags": ["marked"] }
  },
  "pngCommands": [
    ["latex", "-interaction=nonstopmode", "tmp.tex"],
    ["dvipng", "-D", "150", "-T", "tight", "-bg", "Transparent",
      "tmp.dvi", "-o", "tmp.png"]
  ],
  "svgCommands": [
    ["lualatex", "-interaction=nonstopmode", "tmp.tex"],
    ["pdfcrop", "tmp.pdf", "tmp.pdf"],
    ["pdf2svg", "tmp.pdf", "tmp.svg"]
  ],
  "review_show_cards": true
}

Zsh completion

There is also a zsh completion file available. To use it, one may symlink or copy it to a location that is already in ones fpath variable, or one may add the apy/completion directory to the fpath list.

As an example, one may first symlink the _apy file:

mkdir -p ~/.local/zsh-functions
ln -s /path/to/apy/completion/_apy ~/.local/zsh-functions

Then add the following line to ones .zshrc file:

fpath=($HOME/.local/zsh-functions $fpath)

Changelog

See the release history on GitHub. For details, feel free to inspect the commity history.

Relevant resources

Here are a list of relevant resources for learning how to work with the Anki databases and code:

Alternatives

Here are some alternatives to apy from which I've drawn inspiration. I've also added a short note on why I did not just settle for the alternative.

Ankiconnect

Ankiconnect is an Anki plugin 2055492159) hosted on github.

Ankiconnect enables external applications to communicate with Anki over a network interface. The exposed API makes it possible to execute queries against the user’s card deck, automatically create new vocabulary and Kanji flash cards, and more.

A couple of relevant applications that use Ankiconnect:

  • Anki Quick Adder: A Chrome extension to add words to Anki desktop quickly.

  • Anki-editor is an emacs plugin for making Anki cards with Org.

  • anki-cli is a simple nodejs based command-line interface for Anki.

  • trrc is a command-line program to add a card to Anki using AnkiConnect API.

The Dealbreaker: I wanted a script that does not require Anki to be running.

Anki::Import - Anki note generation made easy

Anki::Import (see also here) allows one to "Efficiently generate Anki notes with your text editor for easy import into Anki". Quote:

Inputting notes into Anki can be a tedious chore. Anki::Import lets you you generate Anki notes with your favorite text editor (e.g. vim, BBEdit, Atom, etc.) so you can enter formatted notes into Anki's database more efficiently.

The Dealbreaker: This sounds very good, except there are too many steps. I didn't want to have to open Anki desktop. It should work flawlessly directly from the terminal.

AnkiVim

AnkiVim may be used to "Use vim to rapidly write textfiles immediately importable into anki(1)."

The Dealbreaker: Similar to Anki::Import: I didn't want to have to open Anki desktop. It should work flawlessly directly from the terminal.

Knowledge (Vim plugin)

Knowledge is a Vim plugin for generating flash cards to either Anki or Mnemosyne.

The Dealbreaker: It has a single, open issue, which seems to indicate that the application does not work very well and/or is not well maintained.

Ankisync

Ankisync seems somewhat promising, in that it exposes an API for working with Anki collections from Python. It is a successor to AnkiTools, which is stated to be "an Anki *.apkg and collection.anki2 reader and editor".

The Dealbreaker: It does not include any features to add or edit notes (as far as I could tell).

Genanki

Genanki is a library for generating Anki decks.

The Dealbreaker: It is quite close to being something I wanted, except that it needs to run as a plugin to Anki desktop to generate notes to a local collection. It does not seem to allow editing/adding to a local collection outside of Anki desktop.

inka

inka is a CLI utility for adding flashcards from Markdown files to Anki.

The Dealbreaker: This did not exist when apy was created. It seems to be close to what I would personally be interested in, but today I find apy solves all (or most) of my requirements. Also, inka requires the AnkiConnect plugin.

Obsidian_to_Anki

Obsidian_to_Anki is a plugin to add flashcards from a text or markdown file to Anki. It can also be run from the command-line as a python script. Built with Obsidian markdown syntax in mind.

The Dealbreaker: Requires AnkiConnect.

Markdown2Anki

Markdown2Anki is a Python script that allows you to easily format your cards using Markdown syntax, and then import them into Anki while retaining the structure you gave them.

As many other alternatives, you need to manually import cards. It may provide support for AnkiConnect.

Contributing

The following is a short and simple guide to getting started with contributing and developing the apy code.

Setup

This project uses Poetry as the build system and to manage dependencies.

Install Poetry first if you don't have it already. Fork the repository, then clone your fork and install a local development build of the project using Poetry.

# Clone the forked repo
git clone [email protected]:<username>/apy.git
cd apy/

# Install the project with Poetry
poetry install

Poetry will create a virtual environment for you (see here for where the environment is created). You can either activate this environment yourself then issue commands in the usual way, or you can prefix your commands with poetry run. Example:

poetry run apy --version

Tests

To run the tests, activate the virtual environment and run:

pytest

Alternatively, without activating the environment:

poetry run pytest

Linting

To format the code, run:

poetry run black .

To type-check the code, run:

poetry run mypy src

apy's People

Contributors

adrienlemaire avatar bishopmatthew avatar camoz avatar ckp95 avatar denismaciel avatar dependabot[bot] avatar kianmeng avatar lervag avatar tobrie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

apy's Issues

Suggestion/Question : Text to cards parsers

I'm sorry to intrude in the issues section of the project, but I couldn't find a more appropriate public space to ask

I've been recently interested in the possibility of parsing my notes into Anki cards to auto-generate them directly from text files (e.g. read an "historynotes.md" file, and generate Cloze cards for every date in the file), and I'd like to implement this in the same spirit as this utility. Would such an addition fit into the project, or if not, is there any way to use some parts of project directly to add this utility?
Thanks for your great work, this has been really useful in scripting, keep up the great work!

Feature request: Support for multiple decks

It would be great if there was support for multiple decks.
For example, the syntax for creating a card with apy add in a deck called "Programming" could be:

deck: Programming
model: Basic
tags: marked

# Note

## Front

## Back

Currently it seems that cards are put into the deck that was last used.

Show card type in apy list verbose

This is a follow-up to #27 (comment) in #27.

At the moment, unless there has been a lapse or the card's ease has been changed, there is no way to distinguish new cards from learnt ones.
If the card was already learnt, apy reposition will fail:

$ apy reposition 0 tag:fixme
Can only reposition new cards!
Aborted!

But if I have dozen of cards in the query I'm trying to reposition,] it's very difficult to figure out which one is not new.

Could we see the current type of each cards in apy list -v ?
By card type, I mean seeing "unseen", "young", "mature" as shown in the stats.

markdown option

I have a problem with the markdown extension:

  • It sets a huge data-original-markdown attribute to the containing element
  • Modifying a card on Ankidroid breaks the layout, and then modification will be changed next time I reedit on the computer with markdown.

The only solution I've found at this point is to stop using the markdown plugin, but it appears that you add it by default for Basic cards:

apy/apy/anki.py

Line 357 in e51eac8

if model_name != 'Basic':

Can you allow us to set our preference in apy.json ?

The default could be something like:

{
    "markdown_models": ["Basic"]
}

In my case, I'd set "markdown_models": []

Edit: Checking again on the options, the presets config could be extended to enable/disable markdown as well

Allow Models to be modified

We could get to complicated schema modifications later.

But, for now, I just wanted to rename a few models.

How do we edit notes & cards ?

Hi.

I'm having issues with Anki + Qt5 + Mozc + ibus + Wayland and from today cannot use Japanese within Anki anymore (or I'd have to write text in another window and constantly copy-paste over to the Anki browser).
I found apy as an alternative that would allow me to edit my cards/notes outside of Anki. Thanks for making it!

It's a bit unclear how I should be using apy thought.

Here's the flow I was expecting:

  • apy list -v <pattern> should give me an id next to each match, that I can use in further queries
  • apy edit <id> should open my editor (vim) and let me edit the card/note

But there doesn't seem to be a edit command yet ? 😅
Is it not possible to edit cards with apy ? 😰

Right now, when searching for cards, I see:

$ apy list -v 名簿
reverting to stock json
Q: <div id="kard"> <div class="tags">KanjiInContext meaning:  名簿を作る時、日本ではあいうえお順、英語ではアルファベット順にする。   <script type="text/x-mathjax-config"> MathJax.Hub.processSectionDelay = 0; MathJax.Hub.Config({ me
A: <div id="kard">     <div class="tags" id='tags'>KanjiInContext     meaning:  名簿を作る時、日本ではあいうえお順、英語ではアルファベット順にする。            <div id='extra'>名簿・めいぼ・register / list of names 順・じゅん・order
ease: 250.0% lapses: 0 model: Basic

Q: <div id="kard"> <div class="tags">KanjiInContext reading:  <u>名簿</u>を作成する   <script type="text/x-mathjax-config"> MathJax.Hub.processSectionDelay = 0; MathJax.Hub.Config({ messageStyle:"none", showProce
A: <div id="kard">     <div class="tags" id='tags'>KanjiInContext     reading:  <u>名簿</u>を作成する            <div id='extra'>めいぼ・name roster, list of members  <script type="text/x-mathjax-config"> MathJax.Hub
ease: 250.0% lapses: 0 model: Basic

Q: <div id="kard"> <div class="tags"> <div id="cloze-content">名前を<span class=cloze>[reading 名簿]</span>・<u>戸籍</u>から<u>抹消</u>する  <script> const tags = document.getElementsByClassName("tags")[0].innerHTML.split(" ");
A: <div id="kard">     <div class="tags" id='tags'>     名前を<span class=cloze><u>名簿</u></span>・<u>戸籍</u>から<u>抹消</u>する            <div id='extra'>名簿・めいぼ・register/list of names 戸籍・こ
せき・census, family r
ease: 250.0% lapses: 0 model: Cloze

Q: <div id="kard"> <div class="tags"> <div id="cloze-content">名前を<u>名簿</u>・<span class=cloze>[reading 戸籍]</span>から<u>抹消</u>する  <script> const tags = document.getElementsByClassName("tags")[0].innerHTML.split(" ");
A: <div id="kard">     <div class="tags" id='tags'>     名前を<u>名簿</u>・<span class=cloze><u>戸籍</u></span>から<u>抹消</u>する            <div id='extra'>名簿・めいぼ・register/list of names 戸籍・こ
せき・census, family r
ease: 0.0% lapses: 0 model: Cloze

Q: <div id="kard"> <div class="tags"> <div id="cloze-content">名前を<u>名簿</u>・<u>戸籍</u>から<span class=cloze>[reading 抹消]</span>する  <script> const tags = document.getElementsByClassName("tags")[0].innerHTML.split(" ");
A: <div id="kard">     <div class="tags" id='tags'>     名前を<u>名簿</u>・<u>戸籍</u>から<span class=cloze><u>抹消</u></span>する            <div id='extra'>名簿・めいぼ・register/list of names 戸籍・こ
せき・census, family r
ease: 230.0% lapses: 1 model: Cloze

It's honestly hard to find out what is the card I'm looking for.
After some time reading the output, I understand that the top 2 questions are 2 Basic questions, and the bottom 3 are 1 Cloze question.
The cloze is the one I was looking forward to update.

Operations that I regularly do are:

  • adding tags (using randomize tag to shuffle words in the question with a javascript snippet). apy has that covered, but using matching notes returns several results and I only want to target a single note. I cannot seem able to use html tags in the query ? Allowing ids would be very handy.
    $ apy list -v '前を<u>名簿</u>'
    reverting to stock json
    $ # nothing has been returned!
  • Modifying notes content
  • Converting a basic note to a cloze (assuming that if I could just edit the basic card, and replace its content with cloze content, it would be converted automatically like the Anki addon GODMODE ?)

Really hoping that either all of this is possible and I just missed something, or that you have a roadmap to include these features ❤️

type union syntax breaks on 3.9

syntax like

        exc_type: type[BaseException] | None,

where you use | to mean Union only works on Python 3.10 and higher. this should either be fixed to use Union (or in this case, Optional), or we should bump the required Python version to 3.10.

stdout color formatting

It might be more flexible to rely on external formatting tools to handle coloring the output, and will allow users to customize their colors.

I usually use grc to colorize shell output.
And tools like pygmentize are popular to colorize code.

Eg for this grc conf:

# Colorize apy list output
regexp=\w+
colours="\033[38;5;20m"
count=more
=====
regexp=^(\w+:)
colours=red
count=more
=====
regexp=(cid|ease|lapses|due|model): ([\w.%]+)
colours=yellow, blue
count=more
=====

It's a low priority, but it'd be nice if the output of apy list was more readable, especially when using markdown: false. I'm not sure what would be a good way to achieve that.

Question: How to use latex math formulas in fields?

How can I use latex math formulas within fields for apy add and apy add-from-file.
I could not find a recommended/working way in the documentation.
However, writing formulas with latex is for many anki users an important feature during card creation.

possible future problems with PEP 668

There's this PEP 668. It's meant to stop people using pip to put stuff into the system Python environment and interfering with the distro package manager. It's probably a good thing for the Python ecosystem on net, because so much stuff gets silently broken when people do this. But I think it will cause problems for apy, at least the way it's set up now. The install instructions say to pip install it into the system Python environment so it can import the anki module, but that will no longer work when distributions adopt this PEP. Debian is already doing it, see here.

Not sure what the solution would be other than mandating a virtual environment install. Perhaps resurrect the pipx idea from issue #20? pipx is apparently recommended and maintained by the Python Packaging Authority nowadays, so this could be the way forward.

markdown_models option not working

Added my sub-deck Pro::IT / Tech to the list of markdown models.
Expected: creating a card should show markdown: true
Actual: always seeing markdown: false

Error when trying to run apy command

I installed apy with
pip install -e .
The command apy --help works fine, but when I try to do e.g. apy add, I get:

Traceback (most recent call last):
  File "/home/skervim/anaconda3/envs/rl/bin/apy", line 11, in <module>
    load_entry_point('apy', 'console_scripts', 'apy')()
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/skervim/apy/apy/cli.py", line 57, in add
    with Anki(BASE) as a:
  File "/home/skervim/apy/apy/anki.py", line 14, in __init__
    import anki
ModuleNotFoundError: No module named 'anki'

Display id and allow querying id

Given that a pattern can have several matches, it would be nice to see the id of the note in the apy list output, and use that id with apy review to edit a single note.

Quick look in the db shows that the associate column is called cid

sqlite> pragma table_info(notes);
cid  name   type     notnull  dflt_value  pk
---  -----  -------  -------  ----------  --
0    id     integer  0                    1

Usage:

$ apy list -v 単語
Q: question 1 単語
A: answer 1
ease: 250.0% lapses: 0 model: Basic   id=1

$ API list -v 単語
Q: question 2 単語
A: answer 2
ease: 230.0% lapses: 0 model: Basic   id=2

...
$ apy review -i 2 

I'll admit that the feature is a low-priority, because it's quite easy to press c several time in the apy terminal editor until I reach the proper note, then x to abort.

Config file not found

Running apy --info works. So all the anki related modules have been loaded correctly.

But when running apy info I get a config file not found error. Going through the readme, it felt as in the config file is optional. Is that not the case?

Config file:             Not found
Traceback (most recent call last):
  File "/home/dufferzafar/.local/bin/apy", line 11, in <module>
    load_entry_point('apy==0.1', 'console_scripts', 'apy')()
  File "/usr/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/dufferzafar/.local/lib/python3.8/site-packages/apy/cli.py", line 147, in info
    with Anki(cfg['base']) as a:
  File "/home/dufferzafar/.local/lib/python3.8/site-packages/apy/anki.py", line 28, in __init__
    self._init_load_collection(base, path)
  File "/home/dufferzafar/.local/lib/python3.8/site-packages/apy/anki.py", line 47, in _init_load_collection
    basepath = Path(base)
  File "/usr/lib/python3.8/pathlib.py", line 1033, in __new__
    self = cls._from_parts(args, init=False)
  File "/usr/lib/python3.8/pathlib.py", line 674, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/usr/lib/python3.8/pathlib.py", line 658, in _parse_args
    a = os.fspath(a)
TypeError: expected str, bytes or os.PathLike object, not NoneType

Bug: chosen model (note type) does not override last active model.

I realized that there is apparently still a problem with the selection of the note type.
Let's say, I open anki desktop and add a card of note type "A" to a deck and close it.
Then I try to add a new card with apy add or apy add-from-file of a different note type "B".
Here, if the note types have a different number of fields, the following error will occur (if they have the same number of fields, still the old note type "A" will be chosen and populated with the chosen field values):

Traceback (most recent call last):
  File "/home/skervim/anaconda3/envs/rl/bin/apy", line 11, in <module>
    load_entry_point('apy', 'console_scripts', 'apy')()
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/skervim/apy/apy/cli.py", line 63, in add
    notes = a.add_notes_with_editor(tags, model, deck)
  File "/home/skervim/apy/apy/anki.py", line 322, in add_notes_with_editor
    return self.add_notes_from_file(tf.name)
  File "/home/skervim/apy/apy/anki.py", line 328, in add_notes_from_file
    tags)
  File "/home/skervim/apy/apy/anki.py", line 356, in add_notes_from_list
    note.get('deck')))
  File "/home/skervim/apy/apy/anki.py", line 389, in _add_note
    return Note(self, note)
  File "/home/skervim/apy/apy/note.py", line 11, in __init__
    self.fields = [x for x, y in self.n.items()]
  File "/home/skervim/anki/anki/notes.py", line 89, in items
    for ord, f in sorted(self._fmap.values())]
  File "/home/skervim/anki/anki/notes.py", line 89, in <listcomp>
    for ord, f in sorted(self._fmap.values())]
IndexError: list index out of range

Unfortunately, I couldn't find in the code why this happens, but I assume that chosen note type doesn't successfully override the last active note type and so apy tries to populate the last note type instead of the chosen one.

editor hints

How can we modify the edit_note_.*.md template that is used in apy review ?
I'd like to add some vim modelines to improve my experience, like

<!-- vim: setlocal spell spelllang=cjk -->

To disable english spell-check since I'm almost always editing Japanese documents.

Diff html to update markdown notes

While answering lervag/dotvim#2 (comment) about wiki.vim, I got an idea to resolve my pain point described in #32 and let me use markdown-only notes editable from my phone.

Would it be possible to diff the data-original-markdown content with the html content and sync the markdown accordingly?


Here's an example:

  1. Write a markdown card
    What is the **caiptal of France**? 
  2. It gets synced to anki as
    <div data-original-markdown="AB...YZ">
        What is the <b>caiptal of France</b>?
    </div>
  3. From the phone, fix the typo (since the markdown plugin isn't available, the data-original-markdown attribute is not being updated)
    <div data-original-markdown="AB...YZ">
        What is the <b>capital of France</b>?
    </div>
  4. Syncing back to apy, first extract the data-original-markdown data and re-convert to html, then diff the output
    <div data-original-markdown="AB...YZ">
    -    What is the <b>caiptal of France</b>?
    +    What is the <b>capital of France</b>?
    </div>
  5. Update the markdown card (I suppose that's the hardest part... maybe just extract the differing words with a tool like cmp, and do a find-and-replace operation ?)
    What is the **capital of France**? 
  6. Syncing back to anki, the data-original-markdown content is updated
    <div data-original-markdown="CD...WX">
        What is the <b>capital of France</b>?
    </div>

When I say "Syncing back to apy", I'm just not sure when apy re-extract the markdown from data-original-markdown. If it's on a apy list & co, then doing this operation on a apy review + e could be the least expensive operation.

[Feat] Move note to deck

Not a bug: I forgot to use the `-d` option of `apy add` When I try to add a new card to a sub-deck `Perso::JapaneseOther`, apy fails with the following error:
apy add
reverting to stock json
Traceback (most recent call last):
  File "/home/dori/.local/bin/apy", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/dori/.local/lib/python3.8/site-packages/apy/cli.py", line 116, in add
    notes = a.add_notes_with_editor(tags, model_name, deck)
  File "/home/dori/.local/lib/python3.8/site-packages/apy/anki.py", line 381, in add_notes_with_editor
    return self.add_notes_from_file(tf.name)
  File "/home/dori/.local/lib/python3.8/site-packages/apy/anki.py", line 385, in add_notes_from_file
    return self.add_notes_from_list(markdown_file_to_notes(filename),
  File "/home/dori/.local/lib/python3.8/site-packages/apy/convert.py", line 53, in markdown_file_to_notes
    defaults, notes = _parse_file(filename)
  File "/home/dori/.local/lib/python3.8/site-packages/apy/convert.py", line 154, in _parse_file
    note['fields'][field] = ''
KeyError: 'fields'

It doesn't appear possible to move existing cards to other decks. Can we have this feature supported?

Convert card to new model

I tried to modify a Basic card and convert it as a Cloze card, but the operation is ignored and the card stays a Basic card.

# Note
nid: 1479342529723
- model: Basic
+ model: Cloze
deck: Kanji in Context
tags: KanjiInContext
markdown: false

Would it be possible to support that operation? Or to add another option in the review editor n: Change Note type?

From experience, Anki will ask for a full re-upload of the db in that case, which is slow and problematic if for example I already started my reviews from my phone (the sync would lose that data).
Instead, it would be preferable to create a new note with the desired model, then delete the original one (no syncing issue).

Make using the editor optional

Whenever I start using a new piece of software, I usually have a bunch of design related issues. As in, what would I do differently if I were making it. I'm just opening this issue to be a "catch-all" place for such things. Will keep adding comments as I use apy

unexpected keyword argument `for_deck`

Using the example shown here under number 3, I get:
image
My ~/.config/apy/apy.json:

{
  "base": "/home/danj/.local/share/Anki2/",
  "profile": "danj",
  "query": "tag:leech",
  "presets": {
    "default": { "model": "Custom", "tags": ["marked"] }
  },
  "pngCommands": [
    ["latex", "-interaction=nonstopmode", "tmp.tex"],
    [
      "dvipng",
      "-D",
      "150",
      "-T",
      "tight",
      "-bg",
      "Transparent",
      "tmp.dvi",
      "-o",
      "tmp.png"
    ]
  ],
  "svgCommands": [
    ["lualatex", "-interaction=nonstopmode", "tmp.tex"],
    ["pdfcrop", "tmp.pdf", "tmp.pdf"],
    ["pdf2svg", "tmp.pdf", "tmp.svg"]
  ]
}

apy 0.9.0
anki 2.1.15
void linux 5.15.16_1

GitHub actions issue with caching?

After #59 was merged the GitHub actions step fails due to missing dependency of mypy:

image

I believe this is because of this part:

- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root

But I'm not sure exactly what's wrong. I hope @ckp95 or @denismaciel would be able to help me here?

Bug: adding zero notes causes crash

If you run apy add but change your mind and don't add anything (e.g. straight away pressing :wq in Vim or Ctrl-X in Nano), it crashes:

[ckp95@ckp95-laptop anki]$ apy add
reverting to stock json
Dupe detected, note was not added!
Question:

Traceback (most recent call last):
  File "/home/ckp95/.local/bin/apy", line 8, in <module>
    sys.exit(main())
  File "/home/ckp95/.local/lib/python3.8/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/home/ckp95/.local/lib/python3.8/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/home/ckp95/.local/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/ckp95/.local/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/ckp95/.local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/home/ckp95/.local/lib/python3.8/site-packages/apy/cli.py", line 75, in add
    click.echo(f'Added note to deck: {decks[0]}')
IndexError: list index out of range

`<u>` not interpreted in the editor

Not sure if it's a bug or feature request.

I just created a new card (seems to work well, that's awesome!)

And I noticed that all <b> tags got converted and the inner word made bold (like <b>curriculum</b>.
But <u> tags are not converted.

Is the boldening process made on your side in the editor, or should I be looking elsewhere (zsh, alacritty) for that ?

Thanks for the support!

Problem with adding cards

I finally found some time to try creating cards with apy.

When I try to type apy add into the terminal, my editor opens with:

model: Basic
tags: marked

# Note

## Front

## Back
**CATEGORY**

## Hint

I change it to:

model: Basic
tags: marked

# Note

## Front
What is this?
## Back
This is a test!

## Hint
test

When I exit my editor, the following error occurs:

Database was modified.
Remember to sync!
Traceback (most recent call last):
  File "/home/skervim/anaconda3/envs/rl/bin/apy", line 11, in <module>
    load_entry_point('apy', 'console_scripts', 'apy')()
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/skervim/anaconda3/envs/rl/lib/python3.7/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/skervim/apy/apy/cli.py", line 58, in add
    notes = a.add_notes_with_editor(tags, model)
  File "/home/skervim/apy/apy/anki.py", line 291, in add_notes_with_editor
    return self.add_notes_from_file(tf.name)
  File "/home/skervim/apy/apy/anki.py", line 297, in add_notes_from_file
    tags)
  File "/home/skervim/apy/apy/anki.py", line 324, in add_notes_from_list
    note['markdown']))
  File "/home/skervim/apy/apy/anki.py", line 354, in _add_note
    return Note(self, note)
  File "/home/skervim/apy/apy/note.py", line 11, in __init__
    self.fields = [x for x, y in self.n.items()]
  File "/home/skervim/anki/anki/notes.py", line 89, in items
    for ord, f in sorted(self._fmap.values())]
  File "/home/skervim/anki/anki/notes.py", line 89, in <listcomp>
    for ord, f in sorted(self._fmap.values())]
IndexError: list index out of range

Any idea what I am doing wrong?

Making this work in virtual environments

Various issues (#15 , #13 ) were talking about how to make this work in a virtual environment like pipx.

I've found a hacky workaround for this, but it involves editing the apy source code yourself. I've done this with poetry so far and it seemed to work, I'll try it with pipx later.

Basically, wherever you have apy installed, you need to find the cli.py file and edit the top part so it looks like this instead:

"""A script to interact with the Anki database"""
import os

import click

# ultra-hacky way of getting this to work in a virtual environment
import sys, subprocess

command = "/usr/bin/python -c 'import sys; print(sys.path)'"
new_path = eval(subprocess.check_output(command, shell=True).decode("utf-8"))
# this means it will look on the system python path for imports first,
# then the virtual environment's original path
sys.path = new_path + sys.path

# the aqt_data_folder() function in aqt.utils depends on sys.prefix to
# find what it's looking for; sys.prefix depends on the interpreter used
# to launch the script, which means importing aqt will always fail in a
# virtual environment unless we override sys.prefix temporarily.
old_prefix = sys.prefix
sys.prefix = "/usr"

from apy.anki import Anki
from apy.config import cfg, cfg_file

sys.prefix = old_prefix

# rest of file continues here

You may need to edit the /usr/bin/python part to whatever is the path of the interpreter that your Anki install is using, and the sys.prefix = /usr part to whatever is two directories up from your aqt_data folder (i.e. whatever corresponds to my /usr/share/aqt_data/ on your system).

It works:

[ckp95@ckp95-desktop apy-test]$ poetry run apy --help
reverting to stock json
Usage: apy [OPTIONS] COMMAND [ARGS]...

  A script to interact with the Anki database.

  The base directory may be specified with the -b / --base option. For
  convenience, it may also be specified in the config file
  `~/.config/apy/apy.json` or with the environment variable APY_BASE or
  ANKI_BASE. This should point to the base directory where Anki stores it's
  database and related files. See the Anki documentation for information
  about where this is located on different systems
  (https://apps.ankiweb.net/docs/manual.html#file-locations).

  A few sub commands will open an editor for input. Vim is used by default.
  The input is parsed when one saves and quits. To abort, one should exit
  the editor with a non-zero exit code. In Vim, one can do this with the
  `:cquit` command.

  One may specify a different editor with the EDITOR environment variable.
  For example, to use emacs one can add this to ones `~/.bashrc` (or
  similar) file:

      export EDITOR=emacs

  Note: Use `apy subcmd --help` to get detailed help for a given subcommand.

Options:
  -b, --base TEXT  Set Anki base directory
  -h, --help       Show this message and exit.

Commands:
  add            Add notes interactively from terminal.
  add-from-file  Add notes from Markdown file.
  check-media    Check media
  info           Print some basic statistics.
  list           List cards that match a given query.
  model          Interact with Anki models.
  review         Review marked notes.
  sync           Synchronize collection with AnkiWeb.
  tag            List tags or add/remove tags from matching notes.

I'll leave this open in case anyone has a better way of doing this. Needless to say it's very hacky and could easily get broken by an update to either Anki or apy, so it's just a stopgap.

Error: No module named 'anki' when running 'apy'

I am trying to run apy on my laptop with Linux Mint 21:

Kernel: 5.15.0-56-generic x86_64
Desktop: Cinnamon 5.4.12
Distro: Linux Mint 21 Vanessa (base: Ubuntu 22.04 jammy )

When I run apy info I get the following error:

Traceback (most recent call last):
  File "/home/pietro/.local/bin/apy", line 33, in <module>
    sys.exit(load_entry_point('apy', 'console_scripts', 'apy')())
  File "/home/pietro/.local/bin/apy", line 25, in importlib_load_entry_point
    return next(matches).load()
  File "/usr/lib/python3.10/importlib/metadata/__init__.py", line 171, in load
    module = import_module(match.group('module'))
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/pietro/git/apy/apy/cli.py", line 8, in <module>
    from apy.anki import Anki
  File "/home/pietro/git/apy/apy/anki.py", line 7, in <module>
    import anki
ModuleNotFoundError: No module named 'anki'

This is what I have done before trying running apy:

  1. I installed Anki from the official web site https://apps.ankiweb.net/ (anki-2.1.55-linux-qt6). Anki works well.

  2. I cloned apy repo in $HOME/git/apy

  3. I installed apy with pip install -e .

After getting the error, I searched online and I found this similar issue: #1

Following the solution for the issue #1 I cloned the anki repo (https://github.com/ankitects/anki.git) in $HOME/git/anki

Then I tried the following:

export APY_ANKI_PATH=$HOME/git/anki
apy info

But I still get the same error as above.

Another useful info might be, that I recently changed my laptop. On the previous one, I could use apy without problems (it was really useful!). But I don't remember what I did when I installed it the first time on my old laptop. The only difference is the OS version: on the old one I had Linux Mint 20, on the new one I have Linux Mint 21

Could you help me? Thank you in advance!

`apy add-single` options not working

I am not able to add a single note with this command (as reported in the README):

apy add-single -p preset "Question/Front" "Answer/Back"

But if I run this, it works:

apy add-single --deck <deck_name> "Question/Front" "Answer/Back"

(Currently, I have just one profile and one deck)

Maybe the flag and the options have been changed and the README was not updated.

By the way, great library! I love it!

specifying deck when adding from file?

Hi Karl, got this working with my setup the other day and enjoy it so far, thanks.

I tried implementing the adding cards via Vim example you wrote up in the Wiki. It basically worked, I was wondering if it was possible to control which deck it added the cards to? I tried running it twice as a test, each time it added my cards to different deck.

Feature Request: Imitate frozen field addon

A very useful anki addon for the creation of cards with anki desktop is the frozen field addon.
From its description: "Anki supports sticky fields. A sticky field is a field whose value is not deleted when you switch to a different note. This can be very useful if you are making many notes in which a field either has the same value or changes very little."

It would be awesome if there was a syntax to specify sticky fields for a markdown file from which we create anki cards via apy add-from-file input.md.

Just like it is possible to specify the note type (model) for several notes in advance:

        //input.md
        model: Basic
        tags: marked

        # Note 1
        ## Front
        Question?

        ## Back
        Answer.

        # Note 2
        tag: silly-tag

        ## Front
        Question?

        ## Back
        Answer
    

it would be very useful to determine the value of certain fields for all notes in advance.

AttributeError: '_Collection' object has no attribute 'sched_ver'. Did you mean: 'schedVer'?

Fresh install of Ubuntu 22.04
With Anki 2.1.52-linux-qt6
APY latest version installed

apy -b /home/docker/.local/share/Anki2/
Config file:             Not found
Collecton path:          /home/docker/.local/share/Anki2/edyn/collection.anki2
Traceback (most recent call last):
  File "/home/docker/.local/bin/apy", line 8, in <module>
    sys.exit(main())
  File "/usr/lib/python3/dist-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1637, in invoke
    super().invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/docker/.local/lib/python3.10/site-packages/apy/cli.py", line 54, in main
    ctx.invoke(info)
  File "/usr/lib/python3/dist-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/home/docker/.local/lib/python3.10/site-packages/apy/cli.py", line 183, in info
    click.echo(f"Scheduler version:       {a.col.sched_ver()}")
AttributeError: '_Collection' object has no attribute 'sched_ver'. Did you mean: 'schedVer'?

Feat: reposition new cards

Can we add a r: Reposition card option to the apy editor ?

Reviewing note 1 of 5
c: Continue        e: Edit            a: Add new         d: Delete
m: Toggle markdown *: Toggle marked   z: Toggle suspend  p: Toggle pprint
F: Clear flags     C: Show card names f: Show images     E: Edit CSS
s: Save and stop   x: Abort           r: Reposition card

This is the equivalent of:

If I clicked OK, that would reposition the card from no. 13 to no. 1, and shift the position of other cards.

This is a feature that I use daily, by modifying a pre-existing deck as I study Japanese kanjis with a book.

Bug: Adding notes with `add-from-files` gives them all the "marked" tag

I make a file called stuff.md

model: Basic
deck: All

# Note

## Front

sphinx of black quartz

## Back

judge my vow!

I add it to Anki using

apy add-from-file stuff.md

this gives:

reverting to stock json
Added note to deck: All
Review added notes? [y/N]: n
Database was modified.
Remember to sync!

When I open my Anki database, the note appears but it has the "marked" tag, which I didn't specify and don't want.

image

This doesn't happen when I use apy add and use the interactive mode.

Error on apy --help

Python 3.7.4
Ubuntu 18.04

> apy --help
Traceback (most recent call last):
  File "/home/me/miniconda3/bin/apy", line 11, in <module>
    load_entry_point('apy', 'console_scripts', 'apy')()
  File "/home/me/miniconda3/lib/python3.7/site-packages/pkg_resources/__init__.py", line 489, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/home/me/miniconda3/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2852, in load_entry_point
    return ep.load()
  File "/home/me/miniconda3/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2443, in load
    return self.resolve()
  File "/home/me/miniconda3/lib/python3.7/site-packages/pkg_resources/__init__.py", line 2449, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/home/me/code/apy/apy/cli.py", line 6, in <module>
    from apy.anki import Anki
  File "/home/me/code/apy/apy/anki.py", line 10, in <module>
    from aqt.profiles import ProfileManager
  File "/usr/share/anki/aqt/__init__.py", line 14, in <module>
    from aqt.qt import *
  File "/usr/share/anki/aqt/qt.py", line 6, in <module>
    import sip
ModuleNotFoundError: No module named 'sip'

But I installed sip, strange, any hints, thanks in advance.

Bug: note defaults override chosen model and tag types.

I tried out the new code to test the multiple deck support. I found that here:

apy/apy/convert.py

Lines 55 to 60 in ec22f79

# Add some explicit defaults (unless added in file)
defaults = {**defaults, **{
'markdown': True,
'model': 'Basic',
'tags': 'marked',
}}

the model type and tag type are overriden with the default types due to the {**dict1, **dict2} expression. I think a fix would be to switch the dictionaries in the expression:

defaults = {**{"markdown": True, "model": "Basic", "tags": "marked"}, **defaults}

There's no "RemoteServer" on anki.sync file.

This import is the problem.

from anki.sync import Syncer, RemoteServer

I had to remove that import (and it's usage on the file) because apy crashed at execution. It seems that the official Anki's source code changed and anki.sync.py file doesn't include "RemoteServer" anymore.


#https://github.com/ankitects/anki/blob/master/pylib/anki/sync.py
#This is all the code that's included inside anki.sync.py file



from .httpclient import HttpClient

AnkiRequestsClient = HttpClient


class Syncer:
    def sync(self) -> str:
        pass

I don't know if this is a related issue, or even expected behavior, but after executing
apy info

Anki throws the next error at restart.

erroranki

What do you think? This is related to that conflicting import?

images not shown

Pressing f from the editor menu doesn't change anything:

When I try to reproduce what the code is supposed to do,

apy/apy/note.py

Line 139 in 1ef31eb

subprocess.Popen(['display', '-density', '300', file],

I can display the image:

On a side note, it'd be great if we could configure our image viewer in the settings.
I personally use imv on wayland.

apy --help gives "Exception: couldn't find web folder"

I'm running Manjaro Linux. I installed apy using pipx. My anki is installed with pacman, but the source wasn't in /usr/share/anki/. Instead it looks as though it's in /usr/lib/python3.8/site-packages/ -- at least, there are directories for anki, aqt, and ankirspy in there. So I do export APY_ANKI_PATH=/usr/lib/python3.8/site-packages/

However when I run apy --help I get this output:

reverting to stock json
Traceback (most recent call last):
  File "/home/ckp95/.local/bin/apy", line 5, in <module>
    from apy.cli import main
  File "/home/ckp95/.local/pipx/venvs/apy/lib/python3.8/site-packages/apy/cli.py", line 6, in <module>
    from apy.anki import Anki
  File "/home/ckp95/.local/pipx/venvs/apy/lib/python3.8/site-packages/apy/anki.py", line 10, in <module>
    from aqt.profiles import ProfileManager
  File "/usr/lib/python3.8/site-packages/aqt/__init__.py", line 35, in <module>
    from aqt.main import AnkiQt  # isort:skip
  File "/usr/lib/python3.8/site-packages/aqt/main.py", line 21, in <module>
    import aqt.mediasrv
  File "/usr/lib/python3.8/site-packages/aqt/mediasrv.py", line 31, in <module>
    _exportFolder = _getExportFolder()
  File "/usr/lib/python3.8/site-packages/aqt/mediasrv.py", line 28, in _getExportFolder
    raise Exception("couldn't find web folder")
Exception: couldn't find web folder

I dug around in the mediasrv.py file and found this as the culprit function:

def _getExportFolder():
    data_folder = aqt_data_folder()
    webInSrcFolder = os.path.abspath(os.path.join(data_folder, "web"))
    if os.path.exists(webInSrcFolder):
        return webInSrcFolder
    elif isMac:
        dir = os.path.dirname(os.path.abspath(__file__))
        return os.path.abspath(dir + "/../../Resources/web")
    else:
        raise Exception("couldn't find web folder")


_exportFolder = _getExportFolder()

I stuck a print(data_folder) debug statement in there and ran apy --help again, this is what I got:

/usr/lib/python3.8/site-packages/aqt/../aqt_data

Any idea how to fix?

Can we avoid the dependency on aqt?

One of my biggest peeves with apy is its implicit dependence on Qt. Basically, the code that lets you sync to Ankiweb relies on importing the ProfileManager class, which comes from aqt. And aqt needs PyQT to run. That's a huge pain in the ass to get working on some systems. For example, I just tried installing it again and got

Python 3.10.10 (main, Mar  5 2023, 22:26:53) [GCC 12.2.1 20230201] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import aqt
Running with temporary Qt5 compatibility shims.
Run with DISABLE_QT5_COMPAT=1 to confirm compatibility with Qt6.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/tmp/apy/.venv/lib/python3.10/site-packages/aqt/__init__.py", line 46, in <module>
    from aqt import gui_hooks
  File "/tmp/apy/.venv/lib/python3.10/site-packages/aqt/gui_hooks.py", line 11, in <module>
    from _aqt.hooks import *
  File "/tmp/apy/.venv/lib/python3.10/site-packages/_aqt/hooks.py", line 18, in <module>
    from aqt.qt import QDialog, QEvent, QMenu, QModelIndex, QWidget, QMimeData
  File "/tmp/apy/.venv/lib/python3.10/site-packages/aqt/qt/__init__.py", line 20, in <module>
    from . import qt5_compat  # needs to be imported first
  File "/tmp/apy/.venv/lib/python3.10/site-packages/aqt/qt/qt5_compat.py", line 21, in <module>
    import PyQt6.QtWebEngineCore
ModuleNotFoundError: No module named 'PyQt6.QtWebEngineCore'

In my experience there's always some crap like this where a bunch of dependencies for PyQT don't get installed right, and I waste hours debugging it, then forget what I did when it happens the next time months later.

And IMO it's silly for a purely CLI tool to need a GUI framework as a dependency.

I looked a little closer at the code, and unless I'm mistaken, all we need the ProfileManager class for is to get a SyncAuth object constructed from the profile data. That only relies on the syncKey, currentSyncUrl, customSyncUrl, and networkTimeout keys of the profile. The profile is stored as a pickle blob inside a sqlite file. So couldn't apy just pull out all this data itself? That way we could sever the dependency on aqt, and only rely on the anki package.

Cannot install apy through pipx in Termux as it cannot detect Anki

I've recently tried installing apy through termux via pipx. Unfortunately as it cannot detect any version of anki, it cannot be installed.

I had planned on using apy with AnkiDroid to be able to create flashcards from my phone as well. I already knew the base path of the Anki collections in AnkiDroid. Would this be possible?

Thanks for creating apy btw, it's been great at cutting out unnecessary middleware in my PC.

These are my logs

~/dotfiles $ pipx install git+https://github.com/lervag/apy
Fatal error from pip prevented installation. Full pip output in file:
    /data/data/com.termux/files/home/.local/pipx/logs/cmd_2023-06-21_15.37.13_pip_errors.log

pip seemed to fail to build package:
    git+https://github.com/lervag/apy

Some possibly relevant errors from pip install:
    ERROR: Could not find a version that satisfies the requirement anki<3.0.0,>=2.1.63 (from apy) (from versions: 2.1.24+359b9f5c, 2.1.25, 2.1.26, 2.1.28, 2.1.29, 2.1.30, 2.1.31, 2.1.32, 2.1.33, 2.1.34, 2.1.35)
    ERROR: No matching distribution found for anki<3.0.0,>=2.1.63

Error installing apy from spec
'git+https://github.com/lervag/apy'.

improvement ideas

I really, really like this project and would like to contribute to it. It's such a simple tool, but it has revolutionized the way I interact with Anki.

I have some ideas about what to improve, but would like to get your feedback first, @lervag.

  • Add type hints and type-check the code with MyPy.
  • Auto-format the code with Black
  • Run tests automatically with Github Actions

Do you think these make sense? Let me know if you have other ideas.

Looking forward to contributing!

Review leeches

From #25 (comment), it appears that apy review without query edits all marked and flagged notes.

Please consider also adding leeched cards in the default apy review :) (tag: leech)

That brings another question. How can we query a tag with apy list ? tried apy list 'tag: leech' without success, and apy list leech doesn't search in tags.

Annoyance: apy add leaves markdown files littering the directory

If you run apy add and add some notes interactively, the directory is left with a .md file containing those notes. I think it would be better that they be deleted afterwards by default, or else saved in the /tmp directory.

[ckp95@ckp95-laptop anki]$ ls
[ckp95@ckp95-laptop anki]$ apy add
reverting to stock json
Added note to deck: All
Review added notes? [y/N]: n
Database was modified.
Remember to sync!
[ckp95@ckp95-laptop anki]$ ls
note_4akr_cca.md

New user guide help!

hello I am absolute beginner to terminal and the coding stuff but I did paste the code:

git clone https://github.com/lervag/apy.git
pip install -e .

I downloaded something along the lines of "Command user line tools" which took a bit of time to download. I was suspecting it would install Xcode but now I now it has downloaded the "command line tool for Xcode". and then I pasted the thing same thing again and it downloaded apy.

I see the "apy" folder in MacintoshHD so I know apy is installed. I am typing apy --help in terminal but its saying "command not found : apy" . Do I need to use bash or zsh to run this command and why is it saying "command not found : apy"?

EDIT: I ran the pip3 install --user thegithublink and it installed Markdown, reacher, soup sieve etc which I don't have any idea about.

I was hoping someone would guide me on how to get this working. Thank you.

Error: Path is None on apy add

$ apy add
Traceback (most recent call last):
  File "/home/ali/.local/bin/apy", line 11, in <module>
    load_entry_point('apy==0.1', 'console_scripts', 'apy')()
  File "/home/ali/.local/lib/python3.8/site-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/home/ali/.local/lib/python3.8/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/ali/.local/lib/python3.8/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/ali/.local/lib/python3.8/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/ali/.local/lib/python3.8/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/ali/.local/lib/python3.8/site-packages/apy/cli.py", line 62, in add
    with Anki(cfg['base']) as a:
  File "/home/ali/.local/lib/python3.8/site-packages/apy/anki.py", line 15, in __init__
    self._init_load_collection(base, path)
  File "/home/ali/.local/lib/python3.8/site-packages/apy/anki.py", line 41, in _init_load_collection
    basepath = Path(base)
  File "/usr/lib/python3.8/pathlib.py", line 1018, in __new__
    self = cls._from_parts(args, init=False)
  File "/usr/lib/python3.8/pathlib.py", line 667, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "/usr/lib/python3.8/pathlib.py", line 651, in _parse_args
    a = os.fspath(a)
TypeError: expected str, bytes or os.PathLike object, not NoneType

Anki is at /usr/share/anki
Cloned and pip-installed as in README (not developer version)

ImportError: cannot import name 'MediaSyncer' from 'anki.sync'

❯ apy add -t python -d Python -m Basic-22px

reverting to stock json

Traceback (most recent call last):
  File "/home/dufferzafar/.local/bin/apy", line 11, in <module>
    load_entry_point('apy==0.1', 'console_scripts', 'apy')()
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 490, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2859, in load_entry_point
    return ep.load()
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2450, in load
    return self.resolve()
  File "/usr/lib/python3.8/site-packages/pkg_resources/__init__.py", line 2456, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/home/dufferzafar/.local/lib/python3.8/site-packages/apy/cli.py", line 5, in <module>
    from apy.anki import Anki
  File "/home/dufferzafar/.local/lib/python3.8/site-packages/apy/anki.py", line 10, in <module>
    from anki.sync import Syncer, MediaSyncer, RemoteServer, RemoteMediaServer
ImportError: cannot import name 'MediaSyncer' from 'anki.sync' (/usr/lib/python3.8/site-packages/anki/sync.py)

Haven't debugged this further. Perhaps anki has been updated? Not sure.

Database is NA/locked!

I have followed the instructions but when I execute the apy command it returns the message:
Database is NA/locked!
Aborted

Anyone has been in the same situation? What can I do?

image

Mac/osx: APY_ANKI_PATH related import error

Hi,

My goal was to install Anki-2.1.26 and apy-0.6.0 on my system python (brew install [email protected]), and saving a venv to at least know the python requirements/dependencies that got everything working.

I downloaded the Anki-source code, instead of cloning the git repo and checking out the 2.1.26 version. Which looked like this.

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ ls
.                   README.contributing pylib
..                  README.development  qt
.gitattributes      README.md           rslib
.github             dist                rspy
.gitignore          meta                run
CONTRIBUTORS        pkgkey.asc          scripts
LICENSE             proto
Makefile            pyenv

Note that ~/bin is on my path. After installing all dependencies and sorting out errors from running the ~/bin/anki-2.1.26/run executable, my pip3 list looks similar to

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ pip3 list
Package        Version
-------------- ---------
ankirspy       2.1.26
appdirs        1.4.4
attrs          20.1.0
beautifulsoup4 4.9.1
certifi        2020.6.20
chardet        3.0.4
click          7.1.2
decorator      4.4.2
distlib        0.3.1
filelock       3.0.12
idna           2.10
jsonschema     3.2.0
Markdown       3.2.2
pip            20.1.1
protobuf       3.13.0
PyQt5          5.15.0
PyQt5-sip      12.8.0
PyQtWebEngine  5.15.0
pyrsistent     0.16.0
readchar       2.0.1
requests       2.24.0
Send2Trash     1.5.0
setuptools     49.2.0
six            1.15.0
soupsieve      2.0.1
urllib3        1.25.10
virtualenv     20.0.31
wheel          0.34.2

Next I cloned and installed apy-0.6.0, by using pip3 install . inside the apy directory, adding it to the list above. I also configured the apy paths to

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ env | grep APY
APY_CONFIG=/Users/mikevink/.dotfiles/apy/apy.json
APY_ANKI_PATH=/Users/mikevink/bin/anki-2.1.26

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ cat ~/.dotfiles/apy/apy.json
{
  "base": "/Users/mikevink/Library/Application Support/Anki2"
}

Launching Anki with ~/bin/anki-2.1.26/run works fine at this point, but note that which anki gives anki not found, and when I run apy I get

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ apy
Traceback (most recent call last):
  File "/usr/local/bin/apy", line 5, in <module>
    from apy.cli import main
  File "/usr/local/lib/python3.8/site-packages/apy/cli.py", line 8, in <module>
    from apy.anki import Anki
  File "/usr/local/lib/python3.8/site-packages/apy/anki.py", line 8, in <module>
    import anki
ModuleNotFoundError: No module named 'anki'

My "solution" so far is to set APY_ANKI_PATH=/Users/mikevink/bin/anki-2.1.26/pylib and PYTHONPATH=/Users/mikevink/Documents/python:/Users/mikevink/bin/anki-2.1.26/qt

┏╸~/bin/anki-2.1.26
┗╸❯❯❯ env | grep anki-2.1.26/
APY_ANKI_PATH=/Users/mikevink/bin/anki-2.1.26/pylib
PYTHONPATH=/Users/mikevink/Documents/python:/Users/mikevink/bin/anki-2.1.26/qt

And now apy and Anki works on my fresh system python! Thanks, I have been enjoying it a lot, I also made this reddit post, and if it is oke with you I would like to make a follow up post showing apy in action!

Hope I didn't do something stupid since I'm a little bit of a noob, in any case this shows that currently everything works on Mac/osx, maybe I could make a pull request for building Anki and apy on Mac.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.