I fear putting it in callbacks would be overzealous and reset it
within the processing of the same message, eg. when using conditional
to set the 'ignore' tag before other nested commands run.
Specifically, the issue is with Anonymous using irc.noReply() in
the first call, preventing nested commands' result from being used.
Before this commit, the second and third responses in the test would be
only "1" and "2" instead of "1 ['foo']" and "2 ['foo']".
Before this commit, the plugin first fetched a list of all
(deserialized) records in a list, then reversed the list, and iterated
on the reverse list.
This proved to be slow, with most of the time being spent in
`dbi.DB._newRecord` (which essentially deserializes one list of CSV).
After this commit, the list is reversed first, then the plugin iterates
on its generator, which calls `_newRecord` on records as they are
requested.
This means that when there are many URLs in the database, `@last` does
not need to waste time deserializing most records, when the result is
near the end (and if the result is the first record, then it does
exactly as much work as before).
It is functionally fine not to, but causes objects to never be freed
if iter() is the only method called on the queue (ie. no
enqueue/dequeue, len(), ...)
Not sorting them causes the config file to change when the bot writes
it, because order is nondeterministic.
This is usually fine, but can be annoying when configs are deployed
with Ansible.
Closes GH-1516
With some locale configurations (not that uncommon on CentOS), open() may
default to non-UTF8 encodings (eg. ANSI_X3.4-1968).
This is usually not an issue, because we use open() both for writing and
reading. However, AtomicFile implicitly enforces UTF8; which needs to be
mirrored when reading.
Otherwise, normalization is useless, and gives a surprising error message,
such as:
```
<user> config plugins.rss.sortfeeditems oldestfirst
<bot> Error: Valid values include 'asInFeed', 'oldestFirst', 'newestFirst', 'outdatedFirst', and 'updatedFirst', not 'oldestFirst'.
```
This is consistent with what we already do with commands; and generally
makes sense, as we don't want to re-send titles and others when cycling
on UnrealIRCd (which includes a chathistory batch when joining when
chmode +H is set, despite umode +B)
The previous implementation was messy and needlessly complicated
This simplifies the logic and removes hackiness by making utils/str.py
handle internationalization logic itself, instead of bending over
backwards to load logic from the parent package at import time.
`conf.supybot.databases()` may be called without any plugin supporting
sqlite3 being loaded yet, which causes `sqlite3` to be missing from
`sys.modules`; so it wouldn't be used by plugins loaded afterward.
They are not meant to be displayed like this, so they look weird sometimes.
For example, Mastodon splits long links between spans, so the Fediverse plugin
always displayed them broken.
.getSpecific() always returned the channel-specific but non-network-specific var,
unless the channel-specific and network-specific one was manually set.
`registry.Value.__call__()` is a wrapper around access to
`registry.Value.value`, that checks if the value was set before the latest
call to `registry.open_registry`; and updates the `value` if needed.
When accessing `registry.Value.value` directly, this cache can't be
invalidated, causing the old value to still be used, until the next call
to `registry.Value.__call__()`.