Skip to content

Commit 4749972

Browse files
doc cleanup and test fixes
1 parent 176e1db commit 4749972

File tree

5 files changed

+57
-30
lines changed

5 files changed

+57
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
### Added
2929
* Add `__slots__` and `__eq__` to `FileVersionInfo` for memory usage optimization and ease of testing
3030
* Add support for SSE-C server-side encryption mode
31+
* Add support for `XDG_CONFIG_HOME` for determining the location of `SqliteAccountInfo` db file
3132

3233
### Changed
3334
* `BasicSyncEncryptionSettingsProvider` supports different settings sets for reading and writing

b2sdk/_v2/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from b2sdk.account_info.abstract import AbstractAccountInfo
3535
from b2sdk.account_info.in_memory import InMemoryAccountInfo
3636
from b2sdk.account_info.sqlite_account_info import SqliteAccountInfo
37-
from b2sdk.account_info.sqlite_account_info import B2_ACCOUNT_INFO_ENV_VAR, B2_ACCOUNT_INFO_DEFAULT_FILE
37+
from b2sdk.account_info.sqlite_account_info import B2_ACCOUNT_INFO_ENV_VAR, B2_ACCOUNT_INFO_DEFAULT_FILE, XDG_CONFIG_HOME_ENV_VAR
3838
from b2sdk.account_info.stub import StubAccountInfo
3939
from b2sdk.account_info.upload_url_pool import UploadUrlPool
4040
from b2sdk.account_info.upload_url_pool import UrlPoolAccountInfo

b2sdk/account_info/sqlite_account_info.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
B2_ACCOUNT_INFO_ENV_VAR = 'B2_ACCOUNT_INFO'
2626
B2_ACCOUNT_INFO_DEFAULT_FILE = '~/.b2_account_info'
27+
XDG_CONFIG_HOME_ENV_VAR = 'XDG_CONFIG_HOME'
2728

2829
DEFAULT_ABSOLUTE_MINIMUM_PART_SIZE = 5000000 # this value is used ONLY in migrating db, and in v1 wrapper, it is not
2930
# meant to be a default for other applications
@@ -47,13 +48,14 @@ def __init__(self, file_name=None, last_upgrade_to_run=None):
4748
instead, use ``self.filename`` to get the actual resolved location.
4849
4950
SqliteAccountInfo currently checks locations in the following order:
51+
5052
* ``file_name``, if truthy
51-
* ``B2_ACCOUNT_INFO_ENV_VAR``'s value, if set
52-
* ``~/.b2_account_info``, if it exists
53-
* ``$XDG_CONFIG_HOME/b2/account_info``, if XDG_CONFIG_HOME is set
54-
* ``~/.b2_account_info``, as default
53+
* ``{B2_ACCOUNT_INFO_ENV_VAR}`` env var's value, if set
54+
* ``{B2_ACCOUNT_INFO_DEFAULT_FILE}``, if it exists
55+
* ``{XDG_CONFIG_HOME_ENV_VAR}/b2/account_info``, if ``{XDG_CONFIG_HOME_ENV_VAR}`` env var is set
56+
* ``{B2_ACCOUNT_INFO_DEFAULT_FILE}``, as default
5557
56-
If the directory ``$XDG_CONFIG_HOME/b2`` does not exist, it is created.
58+
If the directory ``{XDG_CONFIG_HOME_ENV_VAR}/b2`` does not exist (and is needed), it is created.
5759
5860
:param str file_name: The sqlite file to use; overrides the default.
5961
:param int last_upgrade_to_run: For testing only, override the auto-update on the db.
@@ -66,8 +68,8 @@ def __init__(self, file_name=None, last_upgrade_to_run=None):
6668
user_account_info_path = os.environ[B2_ACCOUNT_INFO_ENV_VAR]
6769
elif os.path.exists(os.path.expanduser(B2_ACCOUNT_INFO_DEFAULT_FILE)):
6870
user_account_info_path = B2_ACCOUNT_INFO_DEFAULT_FILE
69-
elif 'XDG_CONFIG_HOME' in os.environ:
70-
config_home = os.environ['XDG_CONFIG_HOME']
71+
elif XDG_CONFIG_HOME_ENV_VAR in os.environ:
72+
config_home = os.environ[XDG_CONFIG_HOME_ENV_VAR]
7173
user_account_info_path = os.path.join(config_home, 'b2', 'account_info')
7274
if not os.path.exists(os.path.join(config_home, 'b2')):
7375
os.makedirs(os.path.join(config_home, 'b2'), mode=0o755)
@@ -82,6 +84,16 @@ def __init__(self, file_name=None, last_upgrade_to_run=None):
8284
self._create_tables(conn, last_upgrade_to_run)
8385
super(SqliteAccountInfo, self).__init__()
8486

87+
# dirty trick to use parameters in the docstring
88+
if getattr(__init__, '__doc__', None): # don't break when using `python -oo`
89+
__init__.__doc__ = __init__.__doc__.format(
90+
**dict(
91+
B2_ACCOUNT_INFO_ENV_VAR=B2_ACCOUNT_INFO_ENV_VAR,
92+
B2_ACCOUNT_INFO_DEFAULT_FILE=B2_ACCOUNT_INFO_DEFAULT_FILE,
93+
XDG_CONFIG_HOME_ENV_VAR=XDG_CONFIG_HOME_ENV_VAR,
94+
)
95+
)
96+
8597
def _validate_database(self, last_upgrade_to_run=None):
8698
"""
8799
Make sure that the database is openable. Removes the file if it's not.

b2sdk/v1/account_info.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from abc import abstractmethod
1212
import inspect
1313
import logging
14-
import threading
1514
import os
1615
from typing import Optional
1716

@@ -21,6 +20,7 @@
2120

2221
logger = logging.getLogger(__name__)
2322

23+
2424
# Retain legacy get_minimum_part_size and facilitate for optional s3_api_url
2525
class OldAccountInfoMethods:
2626
@limit_trace_arguments(
@@ -180,16 +180,10 @@ def __init__(self, file_name=None, last_upgrade_to_run=None):
180180
:param int last_upgrade_to_run: For testing only, override the auto-update on the db.
181181
"""
182182
# use legacy env var resolution, XDG not supported
183-
self.thread_local = threading.local()
184-
user_account_info_path = file_name or os.environ.get(
183+
file_name = file_name or os.environ.get(
185184
v2.B2_ACCOUNT_INFO_ENV_VAR, v2.B2_ACCOUNT_INFO_DEFAULT_FILE
186185
)
187-
self.filename = file_name or os.path.expanduser(user_account_info_path)
188-
logger.debug('%s file path to use: %s', self.__class__.__name__, self.filename)
189-
self._validate_database()
190-
with self._get_connection() as conn:
191-
self._create_tables(conn, last_upgrade_to_run)
192-
super(v2.SqliteAccountInfo, self).__init__()
186+
super().__init__(file_name=file_name, last_upgrade_to_run=last_upgrade_to_run)
193187

194188

195189
class StubAccountInfo(MinimumPartSizeTranslator, OldAccountInfoMethods, v2.StubAccountInfo):

test/unit/account_info/test_account_info.py

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,28 @@
1818

1919
import pytest
2020

21-
from apiver_deps import AbstractAccountInfo, InMemoryAccountInfo, UploadUrlPool, SqliteAccountInfo, TempDir, B2_ACCOUNT_INFO_ENV_VAR
21+
from apiver_deps import (
22+
AbstractAccountInfo,
23+
InMemoryAccountInfo,
24+
UploadUrlPool,
25+
SqliteAccountInfo,
26+
TempDir,
27+
B2_ACCOUNT_INFO_ENV_VAR,
28+
XDG_CONFIG_HOME_ENV_VAR,
29+
)
2230
from apiver_deps_exception import CorruptAccountInfo, MissingAccountData
2331

2432
from .fixtures import *
2533

2634

35+
class WindowsSafeTempDir(TempDir):
36+
def __exit__(self, exc_type, exc_val, exc_tb):
37+
try:
38+
super().__exit__(exc_type, exc_val, exc_tb)
39+
except OSError:
40+
pass
41+
42+
2743
class TestAccountInfo:
2844
@pytest.fixture(autouse=True)
2945
def setup(self, account_info_factory, account_info_default_data):
@@ -301,11 +317,11 @@ def setUp(self, request):
301317
self.home = tempfile.mkdtemp()
302318

303319
yield
304-
try:
305-
os.unlink(self.db_path)
306-
except OSError:
307-
pass
308-
shutil.rmtree(self.home)
320+
for cleanup_method in [lambda: os.unlink(self.db_path), lambda: shutil.rmtree(self.home)]:
321+
try:
322+
cleanup_method
323+
except OSError:
324+
pass
309325

310326
def test_corrupted(self):
311327
"""
@@ -360,17 +376,19 @@ def test_uses_default(self):
360376
account_info = self._make_sqlite_account_info(
361377
env={
362378
'HOME': self.home,
379+
'USERPROFILE': self.home,
363380
}
364381
)
365382
actual_path = os.path.abspath(account_info.filename)
366383
assert os.path.join(self.home, '.b2_account_info') == actual_path
367384

368385
def test_uses_xdg_config_home(self, apiver):
369-
with TempDir() as d:
386+
with WindowsSafeTempDir() as d:
370387
account_info = self._make_sqlite_account_info(
371388
env={
372389
'HOME': self.home,
373-
'XDG_CONFIG_HOME': d,
390+
'USERPROFILE': self.home,
391+
XDG_CONFIG_HOME_ENV_VAR: d,
374392
}
375393
)
376394
if apiver in ['v0', 'v1']:
@@ -382,25 +400,27 @@ def test_uses_xdg_config_home(self, apiver):
382400
assert expected_path == actual_path
383401

384402
def test_uses_existing_file_and_ignores_xdg(self):
385-
with TempDir() as d:
403+
with WindowsSafeTempDir() as d:
386404
default_db_file_location = os.path.join(self.home, '.b2_account_info')
387405
open(default_db_file_location, 'a').close()
388406
account_info = self._make_sqlite_account_info(
389407
env={
390408
'HOME': self.home,
391-
'XDG_CONFIG_HOME': d,
409+
'USERPROFILE': self.home,
410+
XDG_CONFIG_HOME_ENV_VAR: d,
392411
}
393412
)
394-
assert not os.path.exists(os.path.join(d, 'b2'))
395413
actual_path = os.path.abspath(account_info.filename)
396414
assert default_db_file_location == actual_path
415+
assert not os.path.exists(os.path.join(d, 'b2'))
397416

398417
def test_account_info_env_var_overrides_xdg_config_home(self):
399-
with TempDir() as d:
418+
with WindowsSafeTempDir() as d:
400419
account_info = self._make_sqlite_account_info(
401420
env={
402421
'HOME': self.home,
403-
'XDG_CONFIG_HOME': d,
422+
'USERPROFILE': self.home,
423+
XDG_CONFIG_HOME_ENV_VAR: d,
404424
B2_ACCOUNT_INFO_ENV_VAR: os.path.join(d, 'b2_account_info'),
405425
}
406426
)

0 commit comments

Comments
 (0)