Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.org
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ slip39 --help 2>&1 | sed 's/^/: /' # (just for output formatting)
: quarter, photo or '(<h>,<w>),<margin>' (default:
: business)
: --no-card Disable PDF SLIP-39 mnemonic card output
: --paper PAPER Paper size (default: Letter)
: --paper PAPER Paper size; Letter, Legal, A4, Photo (default: Letter)
: --cover Produce PDF SLIP-39 cover page
: --no-cover Disable PDF SLIP-39 cover page
: --identifier IDENTIFIER
Expand Down
18 changes: 15 additions & 3 deletions slip39/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from .util import log_cfg, log_level, input_secure
from .layout import write_pdfs
from .defaults import ( # noqa: F401
ANONYMOUS, CARD, CARD_SIZES, PAPER, WALLET, WALLET_SIZES,
ANONYMOUS, CARD, CARD_SIZES, PAPER, PAPER_FORMATS, WALLET, WALLET_SIZES,
BITS, BITS_DEFAULT,
FILENAME_FORMAT,
FILENAME_KEYWORDS,
Expand All @@ -43,6 +43,18 @@
log = logging.getLogger( __package__ )


def paper_format( name ):
"""Convert a (case-insensitive) paper name into its PAPER_FORMATS value (a paper format name, or
(width, height) in mm). Other sizes aren't supported: the cards and Paper Wallets must fit on the
page, and eg. A5 is too small for a Paper Wallet.

"""
for paper,fmt in PAPER_FORMATS.items():
if paper.lower() == name.lower():
return fmt
raise argparse.ArgumentTypeError( f"Unsupported paper size {name!r}; use one of: {', '.join( PAPER_FORMATS )}" )


def main( argv=None ):
ap = argparse.ArgumentParser(
description = "Create and output SLIP-39 encoded Seeds and Paper Wallets to a PDF file.",
Expand Down Expand Up @@ -115,8 +127,8 @@ def main( argv=None ):
ap.add_argument( '--no-card', dest="card", action='store_false',
help="Disable PDF SLIP-39 mnemonic card output" )
ap.add_argument( '--paper',
default=None,
help=f"Paper size (default: {PAPER})" )
default=None, type=paper_format,
help=f"Paper size; {', '.join( PAPER_FORMATS )} (default: {PAPER})" )
ap.add_argument( '--cover', dest="cover_page", action='store_true',
default=True,
help="Produce PDF SLIP-39 cover page" )
Expand Down
31 changes: 31 additions & 0 deletions slip39/main_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import argparse
import pytest

from .defaults import PAPER_FORMATS
from .main import main, paper_format


def test_paper_format():
"""Paper sizes are case-insensitive names from PAPER_FORMATS, converted to their format value."""
assert paper_format( 'a4' ) == paper_format( 'A4' ) == PAPER_FORMATS['A4']
assert paper_format( 'photo' ) == PAPER_FORMATS['Photo'] # eg. (w,h) in mm; not a paper name known to the PDF library
for unsupported in ( 'a5', 'a3', 'tabloid', '' ):
with pytest.raises( argparse.ArgumentTypeError ) as exc:
paper_format( unsupported )
assert "Unsupported paper size" in str( exc.value )
assert all( paper in str( exc.value ) for paper in PAPER_FORMATS )


def test_main_paper( tmp_path, monkeypatch, capsys ):
monkeypatch.chdir( tmp_path )
# An unsupported paper size is refused up front, w/ a one-line message
with pytest.raises( SystemExit ) as exc:
main( [ '-q', '-c', 'BTC', '--paper', 'a5', 'Test' ] )
assert exc.value.code == 2
assert "Unsupported paper size 'a5'" in capsys.readouterr().err
assert not list( tmp_path.glob( '*.pdf' ))

# Supported sizes are produced
for paper in ( 'a4', 'Photo' ):
assert main( [ '-q', '-c', 'BTC', '--paper', paper, '-o', f"paper-{paper}", 'Test' ] ) == 0
assert ( tmp_path / f"paper-{paper}.pdf" ).stat().st_size > 0