Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.

Commit 0d03d49

Browse files
Merge pull request #44 from Serene-Arc/pathlib_switch
Switch to pathlib
2 parents 29c6da8 + f761ef8 commit 0d03d49

File tree

4 files changed

+82
-79
lines changed

4 files changed

+82
-79
lines changed

bak/__main__.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from datetime import datetime
3+
from pathlib import Path
34
from shutil import copy2
45

56
import click
@@ -33,6 +34,7 @@ def create(filename, version):
3334
elif not filename:
3435
__print_help()
3536
else:
37+
filename = Path(filename).expanduser().resolve()
3638
commands.create_bakfile(filename)
3739

3840

@@ -42,6 +44,7 @@ def bak_up(filename):
4244
if not filename:
4345
click.echo("A filename or operation is required.\n"
4446
"\tbak --help")
47+
filename = Path(filename).expanduser().resolve()
4548
if not commands.bak_up_cmd(filename):
4649
# TODO descriptive failures
4750
click.echo("An error occurred.")
@@ -61,6 +64,7 @@ def bak_down(filename, keep, quietly):
6164
if not filename:
6265
click.echo("A filename or operation is required.\n"
6366
"\tbak --help")
67+
filename = Path(filename).expanduser().resolve()
6468
commands.bak_down_cmd(filename, keep, quietly)
6569

6670

@@ -71,18 +75,22 @@ def bak_down(filename, keep, quietly):
7175
help="Delete all related .bakfiles without confirming")
7276
@click.argument("filename", required=True, type=click.Path(exists=True))
7377
def bak_off(filename, quietly):
78+
filename = Path(filename).expanduser().resolve()
7479
if not commands.bak_off_cmd(filename, quietly):
7580
# TODO better output here
7681
click.echo("Operation cancelled or failed.")
7782

83+
7884
@bak.command("open", help="View or edit a .bakfile in an external program")
7985
@click.option("--using", "--in", "--with",
8086
help="Program to open (default: $PAGER or less)",
8187
required=False, hidden=True)
8288
@click.argument("filename", required=True, type=click.Path(exists=True))
8389
def bak_print(filename, using):
90+
filename = Path(filename).expanduser().resolve()
8491
commands.bak_print_cmd(filename, using)
8592

93+
8694
@bak.command("get-bak",
8795
help="Outputs the real path of a .bakfile. "
8896
"Useful for piping, and not much else.",
@@ -91,6 +99,7 @@ def bak_print(filename, using):
9199
required=True,
92100
type=click.Path(exists=True))
93101
def bak_get(to_where_you_once_belonged):
102+
to_where_you_once_belonged = Path(to_where_you_once_belonged).expanduser().resolve()
94103
commands.bak_getfile_cmd(to_where_you_once_belonged)
95104

96105

@@ -101,8 +110,10 @@ def bak_get(to_where_you_once_belonged):
101110
required=False)
102111
@click.argument("filename", required=True, type=click.Path(exists=True))
103112
def bak_diff(filename, using):
113+
filename = Path(filename).expanduser().resolve()
104114
commands.bak_diff_cmd(filename, command=using)
105115

116+
106117
@bak.command("list",
107118
help="List all .bakfiles, or a particular file's")
108119
@click.option("--relpaths",
@@ -111,11 +122,14 @@ def bak_diff(filename, using):
111122
is_flag=True,
112123
default=commands.bak_list_relpaths)
113124
@click.argument("filename",
114-
# help="List a particular file's .bakfiles",
115-
required=False,
116-
type=click.Path(exists=True))
125+
# help="List a particular file's .bakfiles",
126+
required=False,
127+
type=click.Path(exists=True))
117128
def bak_list(relpaths, filename):
129+
if filename:
130+
filename = Path(filename).expanduser().resolve()
118131
commands.show_bak_list(filename=filename or None, relative_paths=relpaths)
119132

133+
120134
if __name__ == "__main__":
121135
bak()

bak/commands/__init__.py

Lines changed: 52 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import os
22
import sqlite3
3+
from pathlib import Path
34

45
from datetime import datetime
5-
from typing import List
6+
from typing import Optional
67
from shutil import copy2
78
from subprocess import call
89
from sys import stderr, stdout
@@ -23,49 +24,37 @@
2324
# TODO: customizable file extension
2425

2526
try:
26-
data_dir = os.environ["XDG_DATA_HOME"]
27+
data_dir = Path(os.environ["XDG_DATA_HOME"]).expanduser().resolve()
2728
except KeyError:
28-
data_dir = os.path.expanduser("~/.local/share")
29+
data_dir = Path("~/.local/share").expanduser().resolve()
2930
try:
30-
config_dir = os.environ["XDG_CONFIG_HOME"]
31+
config_dir = Path(os.environ["XDG_CONFIG_HOME"]).expanduser().resolve()
3132
except KeyError:
32-
config_dir = os.path.expanduser("~/.config")
33+
config_dir = Path("~/.config").expanduser().resolve()
3334

34-
config_file = os.path.join(config_dir, 'bak.cfg')
35-
cfg = Config(config_file)
35+
config_file = config_dir / 'bak.cfg'
36+
cfg = Config(str(config_file))
3637

37-
bak_dir = cfg['bakfile_location'] or os.path.join(data_dir,
38-
"bak", "bakfiles")
39-
bak_db_loc = cfg['bak_database_location'] or \
40-
os.path.join(data_dir, "bak", "bak.db")
38+
bak_dir = cfg['bakfile_location'] or data_dir / 'bak' / 'bakfiles'
39+
bak_db_loc = cfg['bak_database_location'] or data_dir / 'bak' / 'bak.db'
4140

4241
bak_list_relpaths = cfg['bak_list_relative_paths']
4342

44-
if not os.path.exists(bak_dir):
45-
os.makedirs(bak_dir)
43+
if not bak_dir.exists():
44+
bak_dir.mkdir(parents=True)
4645

4746
db_handler = bak_db.BakDBHandler(bak_db_loc)
4847

4948

50-
def expandpath(i_path):
51-
return os.path.abspath(os.path.expanduser(i_path))
52-
53-
54-
def _assemble_bakfile(filename):
49+
def _assemble_bakfile(filename: Path):
5550
time_now = datetime.now()
56-
splitname = os.path.split(expandpath(filename))
57-
bakfile_name = "".join([".".join(i[1:].replace("/", "-")
58-
for i in splitname[:-1]) +
59-
'-' +
60-
splitname[-1],
61-
".",
62-
'-'.join(str(
63-
time_now.timestamp()).split('.')),
64-
".bak"]).replace(" ", "-")
65-
bakfile_path = os.path.join(bak_dir, bakfile_name)
66-
67-
new_bak_entry = bakfile.BakFile(os.path.basename(filename),
68-
os.path.abspath(filename),
51+
bakfile_name = "".join(
52+
["-".join(i for i in filename.parent.parts[1:])
53+
+ '-' + filename.name, ".", '-'.join(str(time_now.timestamp()).split('.')), ".bak"]).replace(" ", "-")
54+
bakfile_path = bak_dir / bakfile_name
55+
56+
new_bak_entry = bakfile.BakFile(filename.name,
57+
filename,
6958
bakfile_path,
7059
time_now,
7160
time_now)
@@ -75,10 +64,10 @@ def _assemble_bakfile(filename):
7564
default_select_prompt = ("Enter a number, or: (V)iew (D)iff (C)ancel", 'C')
7665

7766

78-
def _get_bakfile_entry(filename,
67+
def _get_bakfile_entry(filename: Path,
7968
select_prompt=default_select_prompt,
8069
err=True):
81-
entries = db_handler.get_bakfile_entries(expandpath(filename))
70+
entries = db_handler.get_bakfile_entries(filename.resolve())
8271
if (entries is False) or len(entries) == 0:
8372
return None
8473
# If there's only one bakfile corresponding to filename, return that.
@@ -101,6 +90,7 @@ def _do_select_bakfile(bakfiles: List[bakfile.BakFile],
10190

10291
def get_choice():
10392
return click.prompt(*select_prompt, err=err).lower()
93+
10494
choice = get_choice()
10595

10696
while True:
@@ -142,7 +132,7 @@ def get_choice():
142132
get_choice()
143133

144134

145-
def show_bak_list(filename: (None, str, os.path) = None,
135+
def show_bak_list(filename: Optional[Path] = None,
146136
relative_paths: bool = False):
147137
""" Prints list of .bakfiles with metadata
148138
@@ -153,21 +143,21 @@ def show_bak_list(filename: (None, str, os.path) = None,
153143
# pass
154144
bakfiles: List[bakfile.BakFile]
155145
bakfiles = db_handler.get_bakfile_entries(filename) if filename else \
156-
db_handler.get_all_entries()
146+
db_handler.get_all_entries()
157147

158148
console = Console()
159-
if bakfiles == []:
149+
if bakfiles is []:
160150
console.print(f"No .bakfiles found for "
161-
f"{os.path.abspath(os.path.expanduser(filename))}" if \
162-
filename else "No .bakfiles found")
151+
f"{filename}" if
152+
filename else "No .bakfiles found")
163153
return
164-
165-
_title = f".bakfiles of {os.path.abspath(os.path.expanduser(filename))}" if \
166-
filename else ".bakfiles"
154+
155+
_title = f".bakfiles of {filename}" if \
156+
filename else ".bakfiles"
167157

168158
table = Table(title=_title,
169159
show_lines=True, box=box.HEAVY_EDGE)
170-
160+
171161
table.add_column("")
172162
table.add_column("Original File")
173163
table.add_column("Date Created")
@@ -176,33 +166,33 @@ def show_bak_list(filename: (None, str, os.path) = None,
176166
i = 1
177167
for _bakfile in bakfiles:
178168
table.add_row(str(i),
179-
(os.path.relpath(_bakfile.original_file)) if \
180-
relative_paths else \
169+
(filename.resolve()) if
170+
relative_paths else
181171
_bakfile.orig_abspath,
182172
_bakfile.date_created.split('.')[0],
183173
_bakfile.date_modified.split('.')[0])
184-
i+=1
174+
i += 1
185175

186176
console.print(table)
187177

188-
def create_bakfile(filename: str):
178+
179+
def create_bakfile(filename: Path):
189180
""" Default command. Roughly equivalent to
190181
cp filename $XDG_DATA_DIR/.bakfiles/filename.bak
191182
but inserts relevant metadata into the database.
192183
193184
Arguments:
194185
filename: (str|os.path)
195186
"""
196-
filename = expandpath(filename)
197-
if not os.path.exists(filename):
187+
if not filename.exists():
198188
# TODO descriptive failure
199189
return False
200190
new_bakfile = _assemble_bakfile(filename)
201191
copy2(new_bakfile.orig_abspath, new_bakfile.bakfile_loc)
202192
db_handler.create_bakfile_entry(new_bakfile)
203193

204194

205-
def bak_up_cmd(filename: str):
195+
def bak_up_cmd(filename: Path):
206196
""" Overwrite an existing .bakfile with the file's current contents
207197
208198
Args:
@@ -215,9 +205,8 @@ def bak_up_cmd(filename: str):
215205

216206
console = Console()
217207

218-
filename = expandpath(filename)
219208
old_bakfile = db_handler.get_bakfile_entries(filename)
220-
if old_bakfile == None:
209+
if old_bakfile is None:
221210
console.print(f"No bakfile found for {filename}")
222211
console.print(f"Creating {filename}.bak")
223212
return create_bakfile(filename)
@@ -228,7 +217,7 @@ def bak_up_cmd(filename: str):
228217
select_prompt=(
229218
("Enter a number to overwrite a .bakfile, or:\n(V)iew (L)ist (C)ancel", "C")))
230219

231-
if old_bakfile == None:
220+
if old_bakfile is None:
232221
console.print("Cancelled.")
233222
return True
234223
elif not isinstance(old_bakfile, bakfile.BakFile):
@@ -240,7 +229,7 @@ def bak_up_cmd(filename: str):
240229
return True
241230

242231

243-
def bak_down_cmd(filename: str,
232+
def bak_down_cmd(filename: Path,
244233
keep_bakfile: bool = False,
245234
quiet: bool = False):
246235
""" Restore `filename` from .bakfile. Prompts if ambiguous (such as
@@ -251,7 +240,6 @@ def bak_down_cmd(filename: str,
251240
keep_bakfile (bool): If False, .bakfile is deleted (default: False)
252241
"""
253242
console = Console()
254-
filename = expandpath(filename)
255243
bakfile_entries = db_handler.get_bakfile_entries(filename)
256244
if not bakfile_entries:
257245
console.print(f"No bakfiles found for {filename}")
@@ -260,7 +248,7 @@ def bak_down_cmd(filename: str,
260248
bakfile_entry = _do_select_bakfile(bakfile_entries) if len(
261249
bakfile_entries) > 1 else bakfile_entries[0]
262250

263-
if bakfile_entry == None:
251+
if bakfile_entry is None:
264252
console.print(f"No bakfiles found for {filename}")
265253
return
266254
elif not bakfile_entry:
@@ -295,7 +283,7 @@ def __remove_bakfiles(bakfile_entries):
295283
db_handler.del_bakfile_entry(entry)
296284

297285

298-
def bak_off_cmd(filename: (None, str, os.path),
286+
def bak_off_cmd(filename: Optional[Path],
299287
quietly=False):
300288
""" Used when finished. Deletes `filename.bak`. Prompts if ambiguous:
301289
3 .bakfiles detected:
@@ -310,10 +298,9 @@ def bak_off_cmd(filename: (None, str, os.path),
310298
filename ([type], optional): [description]. Defaults to None.
311299
"""
312300
console = Console()
313-
filename = expandpath(filename)
314301
bakfiles = db_handler.get_bakfile_entries(filename)
315-
if bakfiles == []:
316-
console.print(f"No bakfiles found for {os.path.abspath(filename)}")
302+
if bakfiles is []:
303+
console.print(f"No bakfiles found for {filename}")
317304
return False
318305
confirm = input(
319306
f"Confirming: Remove {len(bakfiles)} .bakfiles for {filename}? "
@@ -336,8 +323,8 @@ def bak_print_cmd(bak_to_print: (str, bakfile.BakFile),
336323
select_prompt=(
337324
"Enter a number to select a .bakfile, or:\n(D)iff (L)ist (C)ancel",
338325
"C"))
339-
# "View which .bakfile? (#)",
340-
# "c"))
326+
# "View which .bakfile? (#)",
327+
# "c"))
341328
if _bak_to_print == None:
342329
console.print(
343330
f"No bakfiles found for {os.path.abspath(bak_to_print)}")
@@ -363,18 +350,18 @@ def bak_getfile_cmd(bak_to_get: (str, bakfile.BakFile)):
363350
print(bak_to_get.bakfile_loc)
364351

365352

366-
def bak_diff_cmd(filename: str, command='diff'):
353+
def bak_diff_cmd(filename: (bakfile.BakFile, Path), command='diff'):
367354
# TODO write tests for this (mildly tricky)
368355
console = Console()
369356

370357
bak_to_diff = filename if isinstance(filename, bakfile.BakFile) else \
371-
_get_bakfile_entry(expandpath(filename),
358+
_get_bakfile_entry(filename.resolve(),
372359
select_prompt=(
373360
("Enter a number to diff a .bakfile, or:\n(V)iew (L)ist (C)ancel", "C")))
374361
if not command:
375362
command = cfg['bak_diff_exec'] or 'diff'
376-
if bak_to_diff == None:
377-
console.print(f"No bakfiles found for {os.path.abspath(filename)}")
363+
if bak_to_diff is None:
364+
console.print(f"No bakfiles found for {filename.resolve()}")
378365
return
379366
if not bak_to_diff:
380367
return

bak/data/bak_db.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import os
22
import sqlite3
3+
from pathlib import Path
34

45
from .bakfile import BakFile
56

67

7-
class BakDBHandler():
8-
db_loc: str
8+
class BakDBHandler:
9+
db_loc: Path
910

10-
def __init__(self, db_loc: str):
11+
def __init__(self, db_loc: Path):
1112
self.db_loc = db_loc
1213

13-
if not os.path.exists(self.db_loc):
14+
if not self.db_loc.exists():
1415
db_conn = sqlite3.connect(self.db_loc)
1516
db_conn.execute("""
1617
CREATE TABLE bakfiles (original_file,

0 commit comments

Comments
 (0)