xgettext and related tools have a -s/--sort-output option, which results in the output being lexicographically sorted. The gettext maintainers recommend against using this option and even started deprecating it in some of their tools (xgettext included):
- with -s, source strings are lexicographically sorted in the .pot/.po files
- without -s, source string are output in the same order they are found in the code
- this way, translators have to do much fewer context switches when contributing translations
note that the qml part we have already *not* been sorting
urllib.parse needs to be explicitly imported for e.g. urllib.parse.urlparse to work.
I think this was not erroring only because urllib.parse is imported in other modules.
Catch JavaError when trying to load the java classes of the biometry
module on startup. This can raise if the device is on an old API version
and the loaded java class depends on apis unknown to the os.
Fixes#10470
```
02-17 10:07:25.714 5254 5270 I python : 0.47 | E | __main__ | daemon.run_gui errored
02-17 10:07:25.714 5254 5270 I python : Traceback (most recent call last):
02-17 10:07:25.714 5254 5270 I python : File "app/main.py", line 514, in handle_cmd
02-17 10:07:25.714 5254 5270 I python : File "app/electrum/daemon.py", line 653, in run_gui
02-17 10:07:25.714 5254 5270 I python : File "app/electrum/gui/qml/__init__.py", line 38, in <module>
02-17 10:07:25.714 5254 5270 I python : File "app/electrum/gui/qml/qeapp.py", line 49, in <module>
02-17 10:07:25.714 5254 5270 I python : File "app/electrum/gui/qml/qebiometrics.py", line 33, in <module>
02-17 10:07:25.714 5254 5270 I python : File "jnius/reflect.py", line 243, in autoclass
02-17 10:07:25.714 5254 5270 I python : File "jnius/jnius_export_class.pxi", line 877, in jnius.jnius.JavaMethod.__call__
02-17 10:07:25.714 5254 5270 I python : File "jnius/jnius_export_class.pxi", line 964, in jnius.jnius.JavaMethod.call_method
02-17 10:07:25.714 5254 5270 I python : File "jnius/jnius_utils.pxi", line 79, in jnius.jnius.check_exception
02-17 10:07:25.714 5254 5270 I python : jnius.jnius.JavaException: JVM exception occurred: Failed resolution of: Landroid/hardware/biometrics/BiometricPrompt$AuthenticationResult; java.lang.NoClassDefFoundError
```
Call `NWCServer.event_handler_task.cancel()` on asyncio thread.
```
File "/home/user/Documents/electrum/electrum/plugins/nwc/nwcserver.py", line 281, in restart_event_handler
self.event_handler_task.cancel()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 829, in call_soon
self._check_thread()
~~~~~~~~~~~~~~~~~~^^
File "/usr/lib64/python3.14/asyncio/base_events.py", line 866, in _check_thread
raise RuntimeError(
"Non-thread-safe operation invoked on an event loop other "
"than the current one")
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
```
Fix exception when clicking on "Donate to server" in offline mode by not
showing the "Donate to server" menu action when no network is set.
Raise CancelledError in `fetch_bitcoin_paper` as
`_fetch_tx_from_network` already shows an according error message so the
second, subsequent error message shown by `on_error` is not useful if
`_fetch_tx_from_network` already failed.
```
63.53 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "/home/user/Documents/electrum/electrum/gui/qt/main_window.py", line 864, in donate_to_server
d = self.network.get_donation_address()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get_donation_address'
```
please, use common sense :(
I guess it was a copy-paste error, but still, treat all _() and qsTr() calls as "scary" and as potential attack vectors. Don't blindly call _(): every call needs to be weighed separately.
Tries to remove differences caused by filesystem-order in the generated .pot file.
The crowdin activity stream is full of events:
```
SomberNight_CI_BOT changed the context of 126 strings
02:42
String Previous context New context File Time
{} blocks #: electrum/gui/qt/channel_details.py:256 #: electrum/gui/qt/channel_details.py:257 electrum/gui/qt/network_dialog.py:514 #: electrum/gui/qt/network_dialog.py:514 electrum/gui/qt/channel_details.py:256 #: electrum/gui/qt/channel_details.py:257 messages.pot 02:42
[...]
```
^ i.e. on every CI push, the comments containing the file paths and line-numbers were getting mixed up randomly
This is undesirable noise.
api key was previously for "SomberNight" crowdin acc, now it's for a fresh acc "SomberNight_CI_BOT".
- "SomberNight_CI_BOT" acc has fewer permissions overall
- the new api key is minimally scoped
- I can't remember what the old api key was scoped to, and crowdin does not show the settings of existing api key, one can only revoke them
- the crowdin audit log can now distinguish actions of the bot vs actions I do manually
I tried to reproduce:
https://github.com/spesmilo/electrum/issues/8815#issuecomment-2094259186
which triggered the following exception for me:
```
Traceback (most recent call last):
File "/home/user/code/electrum-fork/electrum/gui/qt/__init__.py", line 409, in start_new_window
window = self._create_window_for_wallet(wallet)
File "/home/user/code/electrum-fork/electrum/gui/qt/__init__.py", line 329, in _create_window_for_wallet
w = ElectrumWindow(self, wallet)
File "/home/user/code/electrum-fork/electrum/gui/qt/main_window.py", line 290, in __init__
self.load_wallet(wallet)
~~~~~~~~~~~~~~~~^^^^^^^^
File "/home/user/code/electrum-fork/electrum/util.py", line 495, in do_profile
o = func(*args, **kw_args)
File "/home/user/code/electrum-fork/electrum/gui/qt/main_window.py", line 589, in load_wallet
self.update_recently_opened_menu()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/home/user/code/electrum-fork/electrum/gui/qt/main_window.py", line 741, in update_recently_opened_menu
for i, k in enumerate(recent):
~~~~~~~~~^^^^^^^^
TypeError: 'NoneType' object is not iterable
```
This happens because the trustedcoin wallet is loaded outside of
Daemon.load_wallet() so Daemon.update_recently_opened_wallets()
is not getting called and config.RECENTLY:_OPEN_WALLET_FILES is
still None when we try to iterate through it.
As fix i now use load_wallet() instead of manually
instantiating the Wallet
and additionally handle
RECENTLY_OPEN_WALLET_FILES being None in
ElectrumWindow.update_recently_opened_menu().
My pull request https://github.com/spesmilo/electrum/pull/10121
would have sent this exception to the crash reporter so we
might have noticed it earlier. I think we should not just catch
all exceptions in the wizard like on master as it causes us to
repeatedly miss regressions in the wizard that could be sent to
the crash reporter.
Differentiate between the `UserFacingException` and other exceptions
when creating the storage. Forward other exceptions to the reporter so
they can get fixed.
Differentiate between the `UserFacingException` and other exceptions
when creating the storage. Forward other exceptions to the reporter so
they can get fixed.
Modifies `NewWalletWizard.create_storage()` to raise more specific
exception types instead of plain `Exception`. This should allow the
calling GUI to separate between non-bug exceptions (like invalid user
input), and bugs which should not happen and be
passed to the bug reporter.
Adds unittest for Abstract_Wallet.export_history_to_file that
compares the output against reference files. This
should help to prevent regressions and ensure the layout
of the export stays static over time.
Change fees from sats to bitcoin so the fee value is consistent with the
other values.
Fixes#10445
Also adds a plugin hook so plugins can create fancy history exports.
And stops adding unconfirmed/local transactions to the history as they
are unordered and make the export non-deterministic. Also transactions
that haven't happened yet don't seem useful for accounting.
So it can be moved out of HistoryList, get unittested and potentially
used by QML too for example.
Also fix inconsistency between fiat_value and fees_fiat, sometimes if
fiat_value was `No Data` (value=None), fees_fiat was '0' as
fees_fiat.value was Decimal() instead of None.