Case-sensitivity for field names appears to be inconsistent
- Dominant language
- Rust
- Stars
- 30.5k
- Forks
- 3.2k
- Avg merge
- 2d 8h
- Merged PRs (30d)
- 72
Description
Got this error while fuzzing. From tracing through the rust code, it looks like it's implicitly adding a `+` character to deduplicate field names. This can be confirmed by trying this example in the GUI. A `+` is appended to both the field name and its use in the template.
So the field deduplication is case-insensitive, which is in direct conflict with how field replacements work (they are case sensitive). Moreover the [documentation](https://docs.ankiweb.net/templates/fields.html) says fields are case sensitive. This is pretty confusing.
Somewhat unrelated, but I saw https://github.com/ankitects/anki/issues/1979. Not that this is a common pain point, but for what it's worth, I am in favor of dropping custom collations from the DB as they make direct DB ops rather painful.
```python
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = , service = 4, method = 2
input = b'\n\x95\x06{"id":0,"name":"0-d3c25","type":0,"mod":0,"usn":0,"sortf":0,"did":null,"tmpls":[{"name":"0","ord":null,"qf...\\\\setlength{\\\\parindent}{0in}\\n\\\\begin{document}\\n","latexPost":"\\\\end{document}","latexsvg":false,"req":[]}'
def _run_command(self, service: int, method: int, input: bytes) -> bytes:
try:
return self._backend.command(service, method, input)
except Exception as error:
error_bytes = bytes(error.args[0])
err = backend_pb2.BackendError()
err.ParseFromString(error_bytes)
> raise backend_exception_to_pylib(err)
E anki.errors.CardTypeError: Card template 1 in notetype '0-d3c25' has a problem.
See the preview for more information.
E Falsifying example: test_add_notetype(
E data=data(...),
E )
E Draw 1 (add nt: name): '0'
E Draw 2 (add nt: fieldnames): ['A', 'a']
E Draw 3 (add nt: tnames): ['0']
E Draw 4 (add nt: qtxts): ['']
E Draw 5 (add nt: atxts): ['']
E Draw 6 (fmts: placeholders): {'{{A}}'}
E Draw 7 (fmts: frepl locs): [0]
E Draw 8 (fmts: placeholders): {'{{a}}'}
E Draw 9 (fmts: frepl locs): [0]
../../conda/envs/anki/lib/python3.9/site-packages/anki/_backend/__init__.py:146: CardTypeError
==================================================== short test summary info =====================================================
FAILED tests/test_invalid_field_names.py::test_add_notetype - anki.errors.CardTypeError: Card template 1 in notetype '0-d3c2...
======================================================= 1 failed in 16.41s =======================================================
```
```rust
impl Notetype {
pub(crate) fn ensure_names_unique(&mut self) {
let mut names = HashSet::new();
for t in &mut self.templates {
loop {
let name = UniCase::new(t.name.clone());
if !names.contains(&name) {
names.insert(name);
break;
}
t.name.push('+');
}
}
names.clear();
for t in &mut self.fields {
loop {
let name = UniCase::new(t.name.clone());
if !names.contains(&name) {
names.insert(name);
break;
}
t.name.push('+');
}
}
}
```
Contributor guide
Research direction
Start with Notetype::ensure_names_unique in the Rust backend and the failing test in tests/test_invalid_field_names.py. Trace how field names are deduplicated and then resolved in templates, using the A/a reproducer from the issue. Done means the documented case-sensitivity behavior is consistent and the regression test passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, rust
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100