diff --git a/.gitignore b/.gitignore index df29135..3a02080 100644 --- a/.gitignore +++ b/.gitignore @@ -12,10 +12,10 @@ dist .vscode generated -domdiv/fonts/*.otf -domdiv/fonts/*.ttf +src/domdiv/fonts/*.otf +src/domdiv/fonts/*.ttf dominion_dividers.pdf dominion_dividers.png tools/card_db -.mypy_cache/ \ No newline at end of file +.mypy_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..8007a16 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +default_language_version: + # force all unspecified python hooks to run python3 + python: python3 +repos: +- repo: https://github.com/ambv/black + rev: 18.9b0 + hooks: + - id: black +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v2.1.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: flake8 + args: [--max-line-length=120, '--ignore=E203,W503'] + - id: check-json +# - id: pretty-format-json +# args: [--autofix, --no-sort-keys] diff --git a/.travis.yml b/.travis.yml index 3392cca..933c183 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,8 @@ python: install: - pip install -U setuptools - pip install . + - pip install -r requirements.txt # command to run tests -script: python setup.py test +script: + - python setup.py test + - if [[ ${TRAVIS_PYTHON_VERSION:0:1} == "3" ]]; then pre-commit run --all-files; fi diff --git a/MANIFEST.in b/MANIFEST.in index 6319582..c9ea2df 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,5 @@ -recursive-include domdiv/card_db *.json -include domdiv/images/*.png -include domdiv/fonts/*.ttf - +graft src +global-exclude *.py[co] +global-exclude __pycache__ +global-exclude .DS_Store +global-exclude *Minion*.[ot]tf diff --git a/README.md b/README.md index afe7192..0b94edf 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,7 @@ The script has an extensive set of options that are relatively well documented v If you would like to help with translations to new (or updating existing) languages, please see [instructions here](https://github.com/sumpfork/dominiontabs/blob/master/domdiv/card_db/translation.md). -## Prerequisites - -### Python Packages - -You need the python packages for [reportlab](http://www.reportlab.com/software/opensource/rl-toolkit/download/) and [Pillow](https://pypi.org/project/Pillow/) installed. You can install them manually or use the included setup.py via 'python setup.py install' (perhaps run via 'sudo' if not in a virtual env) which should install everything for you. - -### Fonts +## Fonts I believe I cannot distribute one font (Minion Pro) domdiv uses as they are owned by Adobe with a License that I understand to disallow redistribution. @@ -48,8 +42,8 @@ The library will be installed as `domdiv` with the main entry point being `domdi ## Developing -You can use `python setup.py develop` to install the `dominion_dividers` script so that it calls your checked out code, enabling you to run edited code without having to perform an install every time. +Install requirements via `pip install -r requirements.txt`. Then, run `pre-commit install`. You can use `python setup.py develop` to install the `dominion_dividers` script so that it calls your checked out code, enabling you to run edited code without having to perform an install every time. Feel free to comment on boardgamegeek at or file issues on github (). -Tests can be run (and their dependencies installed) via `python setup.py test`. +Tests can be run (and their dependencies installed) via `python setup.py test`, which will also happen if/when you push a branch or make a PR. diff --git a/do_release.py b/do_release.py index d28788a..65bc61e 100644 --- a/do_release.py +++ b/do_release.py @@ -2,16 +2,16 @@ import domdiv import domdiv.main from zipfile import ZipFile, ZIP_DEFLATED -prefix = 'generated/sumpfork_dominion_tabs_' -postfix = 'v' + domdiv.__version__ + '.pdf' +prefix = "generated/sumpfork_dominion_tabs_" +postfix = "v" + domdiv.__version__ + ".pdf" def doit(args, main): - args = args + ' --outfile ' + prefix + main + postfix + args = args + " --outfile " + prefix + main + postfix args = args.split() fname = args[-1] print(args) - print(':::Generating ' + fname) + print(":::Generating " + fname) options = domdiv.main.parse_opts(args) options = domdiv.main.clean_opts(options) domdiv.main.generate(options) @@ -19,20 +19,23 @@ def doit(args, main): argsets = [ - ('', ''), ('--orientation=vertical', 'vertical_'), - ('--papersize=A4', 'A4_'), - ('--papersize=A4 --orientation=vertical', 'vertical_A4_'), - ('--size=sleeved', 'sleeved_'), - ('--size=sleeved --orientation=vertical', 'vertical_sleeved_') + ("", ""), + ("--orientation=vertical", "vertical_"), + ("--papersize=A4", "A4_"), + ("--papersize=A4 --orientation=vertical", "vertical_A4_"), + ("--size=sleeved", "sleeved_"), + ("--size=sleeved --orientation=vertical", "vertical_sleeved_"), ] -additional = ['--expansion-dividers'] +additional = ["--expansion-dividers"] -fnames = [doit(args[0] + ' ' + ' '.join(additional), args[1]) - for args in argsets] +fnames = [doit(args[0] + " " + " ".join(additional), args[1]) for args in argsets] print(fnames) -zip = ZipFile('generated/sumpfork_dominion_tabs_v' + domdiv.__version__ + '.zip', 'w', - ZIP_DEFLATED) +zip = ZipFile( + "generated/sumpfork_dominion_tabs_v" + domdiv.__version__ + ".zip", + "w", + ZIP_DEFLATED, +) for f in fnames: zip.write(f) zip.close() diff --git a/domdiv/__init__.py b/domdiv/__init__.py deleted file mode 100644 index 0fe7c28..0000000 --- a/domdiv/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -import pkg_resources -__version__ = pkg_resources.require('domdiv')[0].version diff --git a/domdiv/fonts/README.md b/domdiv/fonts/README.md deleted file mode 100644 index 23e7b45..0000000 --- a/domdiv/fonts/README.md +++ /dev/null @@ -1,4 +0,0 @@ -#### Fonts -I believe I cannot distribute one font (Minion Pro) domdiv uses as they are commercially sold by Adobe. However, the font files are included with every install of the free Adobe Reader. For example, on Windows 7 they are in C:\Program Files (x86)\Adobe\Reader 9.0\Resource\Font called `MinionPro-Regular.otf`, `MinionPro-Bold.otf` and `MinionPro-It.otf`. - -Sadly, these fonts use features of the otf format that are not support by the reportlab package. Thus, they need to first be converted to ttf (TrueType) format. I used the open source package fontforge to do the conversion. Included as 'convert.ff' is a script for fontforge to do the conversion, on Mac OS X with fontforge installed through macports you can just run `./convert.ff MinionPro-Regular.otf`, `./convert.ff MinionPro-Bold.otf` and `./convert.ff MinionPro-It.otf`. With other fontforge installations, you'll need to change the first line of convert.ff to point to your fontforge executable. I have not done this step under Windows - I imagine it may be possible with a cygwin install of fontforge or some such method. Copy these converted files to this subdirectory. diff --git a/domdiv/tests/text_tab_tests.py b/domdiv/tests/text_tab_tests.py deleted file mode 100644 index ff42d8e..0000000 --- a/domdiv/tests/text_tab_tests.py +++ /dev/null @@ -1,323 +0,0 @@ -from .. import main - - -#################### -# Card Text and Tab Default Test -#################### -def test_text_tabs_default(): - # should be the default - options = main.parse_opts([]) - assert options.text_front == 'card' - assert options.text_back == 'rules' - assert options.tab_name_align == 'left' - assert options.tab_side == 'right-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - -#################### -# Card Text Tests -#################### - - -def test_text_card_rules(): - options = main.parse_opts( - ['--front', 'card', '--back', 'rules']) - assert options.text_front == 'card' - assert options.text_back == 'rules' - - -def test_text_card_blank(): - options = main.parse_opts( - ['--front', 'card', '--back', 'blank']) - assert options.text_front == 'card' - assert options.text_back == 'blank' - - -def test_text_card_card(): - options = main.parse_opts( - ['--front', 'card', '--back', 'card']) - assert options.text_front == 'card' - assert options.text_back == 'card' - - -def test_text_card_none(): - options = main.parse_opts( - ['--front', 'card', '--back', 'none']) - assert options.text_front == 'card' - assert options.text_back == 'none' - - -def test_text_rules_rules(): - options = main.parse_opts( - ['--front', 'rules', '--back', 'rules']) - assert options.text_front == 'rules' - assert options.text_back == 'rules' - - -def test_text_rules_blank(): - options = main.parse_opts( - ['--front', 'rules', '--back', 'blank']) - assert options.text_front == 'rules' - assert options.text_back == 'blank' - - -def test_text_rules_card(): - options = main.parse_opts( - ['--front', 'rules', '--back', 'card']) - assert options.text_front == 'rules' - assert options.text_back == 'card' - - -def test_text_rules_none(): - options = main.parse_opts( - ['--front', 'rules', '--back', 'none']) - assert options.text_front == 'rules' - assert options.text_back == 'none' - - -def test_text_blank_rules(): - options = main.parse_opts( - ['--front', 'blank', '--back', 'rules']) - assert options.text_front == 'blank' - assert options.text_back == 'rules' - - -def test_text_blank_blank(): - options = main.parse_opts( - ['--front', 'blank', '--back', 'blank']) - assert options.text_front == 'blank' - assert options.text_back == 'blank' - - -def test_text_blank_card(): - options = main.parse_opts( - ['--front', 'blank', '--back', 'card']) - assert options.text_front == 'blank' - assert options.text_back == 'card' - - -def test_text_blank_none(): - options = main.parse_opts( - ['--front', 'blank', '--back', 'none']) - assert options.text_front == 'blank' - assert options.text_back == 'none' - -#################### -# Card Tab Tests -#################### -# --tab_name_align left - - -def test_tab_left_left(): - options = main.parse_opts( - ['--tab-name-align', 'left', '--tab-side', 'left']) - assert options.tab_name_align == 'left' - assert options.tab_side == 'left' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - assert options.tab_side == 'left' - - -def test_tab_left_right(): - options = main.parse_opts( - ['--tab-name-align', 'left', '--tab-side', 'right']) - assert options.tab_name_align == 'left' - assert options.tab_side == 'right' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - assert options.tab_side == 'right' - - -def test_tab_left_leftalt(): - options = main.parse_opts( - ['--tab-name-align', 'left', '--tab-side', 'left-alternate']) - assert options.tab_name_align == 'left' - assert options.tab_side == 'left-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - assert options.tab_side == 'left-alternate' - - -def test_tab_left_rightalt(): - options = main.parse_opts( - ['--tab-name-align', 'left', '--tab-side', 'right-alternate']) - assert options.tab_name_align == 'left' - assert options.tab_side == 'right-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - assert options.tab_side == 'right-alternate' - - -def test_tab_left_full(): - options = main.parse_opts( - ['--tab-name-align', 'left', '--tab-side', 'full']) - assert options.tab_name_align == 'left' - assert options.tab_side == 'full' - main.calculate_layout(options) - assert options.tab_name_align == 'left' - assert options.tab_side == 'full' - - # --tab_name_align right - - -def test_tab_right_left(): - options = main.parse_opts( - ['--tab-name-align', 'right', '--tab-side', 'left']) - assert options.tab_name_align == 'right' - assert options.tab_side == 'left' - main.calculate_layout(options) - assert options.tab_name_align == 'right' - assert options.tab_side == 'left' - - -def test_tab_right_right(): - options = main.parse_opts(['--tab-name-align', 'right', '--tab-side', 'right']) - assert options.tab_name_align == 'right' - assert options.tab_side == 'right' - main.calculate_layout(options) - assert options.tab_name_align == 'right' - assert options.tab_side == 'right' - - -def test_tab_right_leftalt(): - options = main.parse_opts( - ['--tab-name-align', 'right', '--tab-side', 'left-alternate']) - assert options.tab_name_align == 'right' - assert options.tab_side == 'left-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'right' - assert options.tab_side == 'left-alternate' - - -def test_tab_right_rightalt(): - options = main.parse_opts( - ['--tab-name-align', 'right', '--tab-side', 'right-alternate']) - assert options.tab_name_align == 'right' - assert options.tab_side == 'right-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'right' - assert options.tab_side == 'right-alternate' - - -def test_tab_right_full(): - options = main.parse_opts( - ['--tab-name-align', 'right', '--tab-side', 'full']) - assert options.tab_name_align == 'right' - assert options.tab_side == 'full' - main.calculate_layout(options) - assert options.tab_name_align == 'right' - assert options.tab_side == 'full' - -# --tab_name_align edge - - -def test_tab_edge_left(): - options = main.parse_opts( - ['--tab-name-align', 'edge', '--tab-side', 'left']) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'left' - main.calculate_layout(options) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'left' - - -def test_tab_edge_right(): - options = main.parse_opts( - ['--tab-name-align', 'edge', '--tab-side', 'right']) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'right' - main.calculate_layout(options) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'right' - - -def test_tab_edge_leftalt(): - options = main.parse_opts( - ['--tab-name-align', 'edge', '--tab-side', 'left-alternate']) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'left-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'left-alternate' - - -def test_tab_edge_rightalt(): - options = main.parse_opts( - ['--tab-name-align', 'edge', '--tab-side', 'right-alternate']) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'right-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'right-alternate' - - -def test_tab_edge_full(): - options = main.parse_opts( - ['--tab-name-align', 'edge', '--tab-side', 'full']) - assert options.tab_name_align == 'edge' - assert options.tab_side == 'full' - options = main.clean_opts(options) - main.calculate_layout(options) - assert options.tab_name_align == 'left' # special check for odd condition - assert options.tab_side == 'full' - - # --tab_name_align centre - - -def test_tab_centre_left(): - options = main.parse_opts(['--tab-name-align', 'centre', '--tab-side', 'left']) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'left' - main.calculate_layout(options) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'left' - - -def test_tab_centre_right(): - options = main.parse_opts(['--tab-name-align', 'centre', '--tab-side', 'right']) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'right' - main.calculate_layout(options) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'right' - - -def test_tab_centre_leftalt(): - options = main.parse_opts( - ['--tab-name-align', 'centre', '--tab-side', 'left-alternate']) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'left-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'left-alternate' - - -def test_tab_centre_rightalt(): - options = main.parse_opts( - ['--tab-name-align', 'centre', '--tab-side', 'right-alternate']) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'right-alternate' - main.calculate_layout(options) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'right-alternate' - - -def test_tab_centre_full(): - options = main.parse_opts(['--tab-name-align', 'centre', '--tab-side', 'full']) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'full' - main.calculate_layout(options) - assert options.tab_name_align == 'centre' - assert options.tab_side == 'full' - -# --tab_name_align center. Just do one since this is an alias to centre - - -def test_tab_center_left(): - options = main.parse_opts(['--tab-name-align', 'center', '--tab-side', 'left']) - assert options.tab_name_align == 'center' - assert options.tab_side == 'left' - options = main.clean_opts(options) - main.calculate_layout(options) - assert options.tab_name_align == 'centre' # check for change in value - assert options.tab_side == 'left' diff --git a/requirements.in b/requirements.in new file mode 100644 index 0000000..3e35cb5 --- /dev/null +++ b/requirements.in @@ -0,0 +1,5 @@ +reportlab +Pillow +pre-commit +pytest +six diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4b7c9f0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,25 @@ +# +# This file is autogenerated by pip-compile +# To update, run: +# +# pip-compile --output-file requirements.txt requirements.in +# +aspy.yaml==1.1.1 # via pre-commit +atomicwrites==1.2.1 # via pytest +attrs==18.2.0 # via pytest +cfgv==1.4.0 # via pre-commit +identify==1.1.8 # via pre-commit +importlib-metadata==0.8 # via pre-commit +more-itertools==5.0.0 # via pytest +nodeenv==1.3.3 # via pre-commit +pillow==5.4.1 +pluggy==0.8.1 # via pytest +pre-commit==1.14.2 +py==1.7.0 # via pytest +pytest==4.1.1 +pyyaml==3.13 # via aspy.yaml, pre-commit +reportlab==3.5.12 +six==1.12.0 +toml==0.10.0 # via pre-commit +virtualenv==16.2.0 # via pre-commit +zipp==0.3.3 # via importlib-metadata diff --git a/setup.cfg b/setup.cfg index 17d2161..03b753f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,11 @@ [metadata] description-file = README.md [tool:pytest] -python_files=*tests.py +python_files = *tests.py addopts = --flake8 +testpaths = tests [aliases] -test=pytest +test = pytest [flake8] -max-line-length=120 +max-line-length = 120 +ignore = E203,W503 diff --git a/setup.py b/setup.py index 49f0a54..8b0233b 100644 --- a/setup.py +++ b/setup.py @@ -1,26 +1,22 @@ -from setuptools import setup, find_packages +from setuptools import setup -version = '3.7.1' +version = "3.7.1" setup( name="domdiv", version=version, - entry_points={ - 'console_scripts': [ - "dominion_dividers = domdiv.main:main" - ], - }, - packages=find_packages(exclude=['tests']), - install_requires=["reportlab==3.5.17", - "Pillow==5.3.0"], + entry_points={"console_scripts": ["dominion_dividers = domdiv.main:main"]}, + package_dir={"": "src"}, + packages=["domdiv"], + install_requires=["reportlab==3.5.17", "Pillow==5.4.1"], setup_requires=["pytest-runner"], - tests_require=["pytest", "pytest-flake8", "six"], - url='http://domtabs.sandflea.org', + tests_require=["pytest", "six", "pytest-flake8", "pre-commit"], + url="http://domtabs.sandflea.org", include_package_data=True, author="Peter Gorniak", author_email="sumpfork@mailmight.net", description="Divider Generation for the Dominion Card Game", - keywords=['boardgame', 'cardgame', 'dividers'], + keywords=["boardgame", "cardgame", "dividers"], long_description="This script and library generate dividers for the Dominion Card Game by Rio Grande Games.\ - See it in action at http://domtabs.sandflea.org." + See it in action at http://domtabs.sandflea.org.", ) diff --git a/src/domdiv/__init__.py b/src/domdiv/__init__.py new file mode 100644 index 0000000..d949528 --- /dev/null +++ b/src/domdiv/__init__.py @@ -0,0 +1,3 @@ +import pkg_resources + +__version__ = pkg_resources.require("domdiv")[0].version diff --git a/domdiv/card_db/cards_db.json b/src/domdiv/card_db/cards_db.json similarity index 100% rename from domdiv/card_db/cards_db.json rename to src/domdiv/card_db/cards_db.json diff --git a/domdiv/card_db/cz/bonuses_cz.json b/src/domdiv/card_db/cz/bonuses_cz.json similarity index 100% rename from domdiv/card_db/cz/bonuses_cz.json rename to src/domdiv/card_db/cz/bonuses_cz.json diff --git a/domdiv/card_db/cz/cards_cz.json b/src/domdiv/card_db/cz/cards_cz.json similarity index 100% rename from domdiv/card_db/cz/cards_cz.json rename to src/domdiv/card_db/cz/cards_cz.json diff --git a/domdiv/card_db/cz/sets_cz.json b/src/domdiv/card_db/cz/sets_cz.json similarity index 100% rename from domdiv/card_db/cz/sets_cz.json rename to src/domdiv/card_db/cz/sets_cz.json diff --git a/domdiv/card_db/cz/types_cz.json b/src/domdiv/card_db/cz/types_cz.json similarity index 100% rename from domdiv/card_db/cz/types_cz.json rename to src/domdiv/card_db/cz/types_cz.json diff --git a/domdiv/card_db/de/bonuses_de.json b/src/domdiv/card_db/de/bonuses_de.json similarity index 92% rename from domdiv/card_db/de/bonuses_de.json rename to src/domdiv/card_db/de/bonuses_de.json index 7579be6..0ed80d6 100644 --- a/domdiv/card_db/de/bonuses_de.json +++ b/src/domdiv/card_db/de/bonuses_de.json @@ -1,7 +1,7 @@ { "exclude": [ "Token", - "Tokens", + "Tokens", "Marker" ], "include": [ @@ -16,4 +16,4 @@ "Punkt", "Punkte" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/de/cards_de.json b/src/domdiv/card_db/de/cards_de.json similarity index 100% rename from domdiv/card_db/de/cards_de.json rename to src/domdiv/card_db/de/cards_de.json diff --git a/domdiv/card_db/de/sets_de.json b/src/domdiv/card_db/de/sets_de.json similarity index 100% rename from domdiv/card_db/de/sets_de.json rename to src/domdiv/card_db/de/sets_de.json diff --git a/domdiv/card_db/de/types_de.json b/src/domdiv/card_db/de/types_de.json similarity index 100% rename from domdiv/card_db/de/types_de.json rename to src/domdiv/card_db/de/types_de.json diff --git a/domdiv/card_db/en_us/bonuses_en_us.json b/src/domdiv/card_db/en_us/bonuses_en_us.json similarity index 99% rename from domdiv/card_db/en_us/bonuses_en_us.json rename to src/domdiv/card_db/en_us/bonuses_en_us.json index 1e5bda9..6bd0b7d 100644 --- a/domdiv/card_db/en_us/bonuses_en_us.json +++ b/src/domdiv/card_db/en_us/bonuses_en_us.json @@ -18,4 +18,4 @@ "Villagers", "" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/en_us/cards_en_us.json b/src/domdiv/card_db/en_us/cards_en_us.json similarity index 100% rename from domdiv/card_db/en_us/cards_en_us.json rename to src/domdiv/card_db/en_us/cards_en_us.json diff --git a/domdiv/card_db/en_us/sets_en_us.json b/src/domdiv/card_db/en_us/sets_en_us.json similarity index 100% rename from domdiv/card_db/en_us/sets_en_us.json rename to src/domdiv/card_db/en_us/sets_en_us.json diff --git a/domdiv/card_db/en_us/types_en_us.json b/src/domdiv/card_db/en_us/types_en_us.json similarity index 100% rename from domdiv/card_db/en_us/types_en_us.json rename to src/domdiv/card_db/en_us/types_en_us.json diff --git a/domdiv/card_db/fr/bonuses_fr.json b/src/domdiv/card_db/fr/bonuses_fr.json similarity index 99% rename from domdiv/card_db/fr/bonuses_fr.json rename to src/domdiv/card_db/fr/bonuses_fr.json index 008c7fe..5e5adac 100644 --- a/domdiv/card_db/fr/bonuses_fr.json +++ b/src/domdiv/card_db/fr/bonuses_fr.json @@ -19,4 +19,4 @@ "Actions", "Action" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/fr/cards_fr.json b/src/domdiv/card_db/fr/cards_fr.json similarity index 100% rename from domdiv/card_db/fr/cards_fr.json rename to src/domdiv/card_db/fr/cards_fr.json diff --git a/domdiv/card_db/fr/sets_fr.json b/src/domdiv/card_db/fr/sets_fr.json similarity index 100% rename from domdiv/card_db/fr/sets_fr.json rename to src/domdiv/card_db/fr/sets_fr.json diff --git a/domdiv/card_db/fr/types_fr.json b/src/domdiv/card_db/fr/types_fr.json similarity index 100% rename from domdiv/card_db/fr/types_fr.json rename to src/domdiv/card_db/fr/types_fr.json diff --git a/domdiv/card_db/it/bonuses_it.json b/src/domdiv/card_db/it/bonuses_it.json similarity index 99% rename from domdiv/card_db/it/bonuses_it.json rename to src/domdiv/card_db/it/bonuses_it.json index 45d9b42..dd53f9a 100644 --- a/domdiv/card_db/it/bonuses_it.json +++ b/src/domdiv/card_db/it/bonuses_it.json @@ -13,4 +13,4 @@ "Azioni", "Azione" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/it/cards_it.json b/src/domdiv/card_db/it/cards_it.json similarity index 100% rename from domdiv/card_db/it/cards_it.json rename to src/domdiv/card_db/it/cards_it.json diff --git a/domdiv/card_db/it/sets_it.json b/src/domdiv/card_db/it/sets_it.json similarity index 100% rename from domdiv/card_db/it/sets_it.json rename to src/domdiv/card_db/it/sets_it.json diff --git a/domdiv/card_db/it/types_it.json b/src/domdiv/card_db/it/types_it.json similarity index 100% rename from domdiv/card_db/it/types_it.json rename to src/domdiv/card_db/it/types_it.json diff --git a/domdiv/card_db/labels_db.json b/src/domdiv/card_db/labels_db.json similarity index 100% rename from domdiv/card_db/labels_db.json rename to src/domdiv/card_db/labels_db.json diff --git a/domdiv/card_db/nl_du/bonuses_nl_du.json b/src/domdiv/card_db/nl_du/bonuses_nl_du.json similarity index 99% rename from domdiv/card_db/nl_du/bonuses_nl_du.json rename to src/domdiv/card_db/nl_du/bonuses_nl_du.json index 220673a..5a00574 100644 --- a/domdiv/card_db/nl_du/bonuses_nl_du.json +++ b/src/domdiv/card_db/nl_du/bonuses_nl_du.json @@ -14,4 +14,4 @@ "Acties", "Actie" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/nl_du/cards_nl_du.json b/src/domdiv/card_db/nl_du/cards_nl_du.json similarity index 100% rename from domdiv/card_db/nl_du/cards_nl_du.json rename to src/domdiv/card_db/nl_du/cards_nl_du.json diff --git a/domdiv/card_db/nl_du/sets_nl_du.json b/src/domdiv/card_db/nl_du/sets_nl_du.json similarity index 100% rename from domdiv/card_db/nl_du/sets_nl_du.json rename to src/domdiv/card_db/nl_du/sets_nl_du.json diff --git a/domdiv/card_db/nl_du/types_nl_du.json b/src/domdiv/card_db/nl_du/types_nl_du.json similarity index 100% rename from domdiv/card_db/nl_du/types_nl_du.json rename to src/domdiv/card_db/nl_du/types_nl_du.json diff --git a/domdiv/card_db/sets_db.json b/src/domdiv/card_db/sets_db.json similarity index 100% rename from domdiv/card_db/sets_db.json rename to src/domdiv/card_db/sets_db.json diff --git a/domdiv/card_db/translation.md b/src/domdiv/card_db/translation.md similarity index 98% rename from domdiv/card_db/translation.md rename to src/domdiv/card_db/translation.md index 67e3616..e4d1ed3 100644 --- a/domdiv/card_db/translation.md +++ b/src/domdiv/card_db/translation.md @@ -19,7 +19,7 @@ The files: cards_xx.json sets_xx.json types_xx.json - + must be encoded in ISO 8859-15, also known as "Latin alphabet no. 9" This character set is used throughout the Americas, Western Europe, Oceania, and much of Africa. It is also commonly used in most standard romanizations of East-Asian languages. @@ -64,13 +64,13 @@ The items in the `include` list are items that will be marked **bold** (i.e., `< when found in the card text in the following format: `+# item_from_include_list` - + as long as this is not followed by a item from the `exclude` list. For example in English: `+2 Buys` will be made bold, but `+1 Action token` will not, since the key word token follows. -- Just replace the English terms with the terms used in the target language. +- Just replace the English terms with the terms used in the target language. - Generally you should include the singular as well as the plural version of the term. - English versions do not need to be duplicated, since they are used automatically. - The key words `exclude` and `include` MUST NOT BE CHANGED. @@ -80,7 +80,7 @@ For example in English: Entries in this file represent Dominion card types. A typical entry looks like: "Action": "Action in new language", - + - The type key word (i.e., the `Action` for the above entry) MUST NOT BE CHANGED. This value is used to identify the translation entry. - Do not change any punctuation outside of the quotes `"`. For example, brackets `{` or `}`, colons `:`, quotes `"` or commas `,`. @@ -104,7 +104,7 @@ For example: - if you provided the `name` of the card, and only the `name`, then change to `description, extra` - if you provided the `name` of the card and it's `description`, but have not translated the `extra`, then change to `extra` - if you provided all 3 entries, then change to `""` - + The "untranslated" entry is used during maintanance of the language files to update any remaining default language entries that might have changed. @@ -154,28 +154,27 @@ IMPORTANT: To keep the special images, please do not translate any of the above - If bonuses_xx.json for the target language is configured correctly, bonuses within the text will automatically be bolded. In English, it will not bold the text if it is followed by `token` or `Token`. Example: - + `Choose one: +3 Cards; or +2 Actions.` will bold `+3 Cards` and `+2 Actions`. - Bonuses should be listed in the following order: * `+ Cards`, - * `+ Actions`, - * `+ Buys`, - * `+ Coins`, + * `+ Actions`, + * `+ Buys`, + * `+ Coins`, * `+ ` - When possible, bonuses should be listed vertically and centered. Examples: * `+1 Card
+1 Action
+1 Buy
+1 Coin
+2 ` * `+1 Card\n+1 Action\n+1 Buy\n+1 Coin\n+2 \n` - + The `description` field by default is centered. `
`, ``, and `\n` will all provide new lines. - If a Dividers/Tab has more than one card explanation, if space permits, try to mimic a stand alone Dividers/Tab in the overall format. Example from "Settlers - Bustling Village": - `Settlers:+1 Card
+1 ActionLook through your discard pile. + `Settlers:+1 Card
+1 ActionLook through your discard pile. You may reveal a Copper from it and put it into your hand. Bustling Village:
+1 Card
+3 Actions Look through your discard pile. You may reveal a Settlers from it and put it into your hand.` - diff --git a/domdiv/card_db/types_db.json b/src/domdiv/card_db/types_db.json similarity index 100% rename from domdiv/card_db/types_db.json rename to src/domdiv/card_db/types_db.json diff --git a/domdiv/card_db/xx/bonuses_xx.json b/src/domdiv/card_db/xx/bonuses_xx.json similarity index 99% rename from domdiv/card_db/xx/bonuses_xx.json rename to src/domdiv/card_db/xx/bonuses_xx.json index 1e5bda9..6bd0b7d 100644 --- a/domdiv/card_db/xx/bonuses_xx.json +++ b/src/domdiv/card_db/xx/bonuses_xx.json @@ -18,4 +18,4 @@ "Villagers", "" ] -} \ No newline at end of file +} diff --git a/domdiv/card_db/xx/cards_xx.json b/src/domdiv/card_db/xx/cards_xx.json similarity index 100% rename from domdiv/card_db/xx/cards_xx.json rename to src/domdiv/card_db/xx/cards_xx.json diff --git a/domdiv/card_db/xx/sets_xx.json b/src/domdiv/card_db/xx/sets_xx.json similarity index 100% rename from domdiv/card_db/xx/sets_xx.json rename to src/domdiv/card_db/xx/sets_xx.json diff --git a/domdiv/card_db/xx/translation.txt b/src/domdiv/card_db/xx/translation.txt similarity index 99% rename from domdiv/card_db/xx/translation.txt rename to src/domdiv/card_db/xx/translation.txt index 2b24030..d15eb15 100644 --- a/domdiv/card_db/xx/translation.txt +++ b/src/domdiv/card_db/xx/translation.txt @@ -47,7 +47,7 @@ For example in English: "+2 Buys" will be made bold, but "+1 Action token" will not, since the key word token follows. -Just replace the English terms with the terms used in the target language. +Just replace the English terms with the terms used in the target language. Generally you should include the singular as well as the plural version of the term. English versions do not need to be duplicated, since they are used automatically. The key words "exclude" and "include" MUST NOT BE CHANGED. @@ -135,4 +135,3 @@ Special character sequences are recognized by the program to substitute graphics - If a Dividers/Tab has more than one card explanation, if space permits, try to mimic a stand alone Dividers/Tab in the overall format. Example from "Settlers - Bustling Village": "Settlers:+1 Card
+1 ActionLook through your discard pile. You may reveal a Copper from it and put it into your hand.Bustling Village:
+1 Card
+3 ActionsLook through your discard pile. You may reveal a Settlers from it and put it into your hand." - diff --git a/domdiv/card_db/xx/types_xx.json b/src/domdiv/card_db/xx/types_xx.json similarity index 100% rename from domdiv/card_db/xx/types_xx.json rename to src/domdiv/card_db/xx/types_xx.json diff --git a/domdiv/cards.py b/src/domdiv/cards.py similarity index 69% rename from domdiv/cards.py rename to src/domdiv/cards.py index 500d7e5..c18ddc1 100644 --- a/domdiv/cards.py +++ b/src/domdiv/cards.py @@ -12,7 +12,6 @@ class Card(object): bonus_regex = None class CardJSONEncoder(json.JSONEncoder): - def default(self, obj): if isinstance(obj, Card): return obj.__dict__ @@ -22,10 +21,26 @@ class Card(object): def decode_json(obj): return Card(**obj) - def __init__(self, name=None, cardset='', types=None, cost='', description='', - potcost=0, debtcost=0, extra='', count=-1, card_tag='missing card_tag', - cardset_tags=None, group_tag='', group_top=False, image=None, - text_icon=None, randomizer=True, cardset_tag=''): + def __init__( + self, + name=None, + cardset="", + types=None, + cost="", + description="", + potcost=0, + debtcost=0, + extra="", + count=-1, + card_tag="missing card_tag", + cardset_tags=None, + group_tag="", + group_top=False, + image=None, + text_icon=None, + randomizer=True, + cardset_tag="", + ): if types is None: types = [] # make sure types is a list @@ -77,7 +92,7 @@ class Card(object): def getBonusBoldText(self, text): for regex in Card.bonus_regex: - text = re.sub(regex, '\\1', text) + text = re.sub(regex, "\\1", text) return text @staticmethod @@ -91,25 +106,25 @@ class Card(object): # Make sure have minimum to to anything if not isinstance(bonus, dict): return - if 'include' not in bonus: + if "include" not in bonus: return - if not bonus['include']: + if not bonus["include"]: return - if 'exclude' not in bonus: - bonus['exclude'] = [] + if "exclude" not in bonus: + bonus["exclude"] = [] # Start processing of lists into a single regex statement # (?i) makes this case insensitive # (?!\) and (?!\<\/b\>) prevents matching already bolded items # (?!\w) prevents smaller word matches. Prevents matching "Action" in "Actions" - if bonus['exclude']: - bonus['exclude'].sort(reverse=True) - exclude_regex = r'(?!\w)(?!\s*(' + '|'.join(bonus['exclude']) + '))' + if bonus["exclude"]: + bonus["exclude"].sort(reverse=True) + exclude_regex = r"(?!\w)(?!\s*(" + "|".join(bonus["exclude"]) + "))" else: - exclude_regex = '' + exclude_regex = "" - bonus['include'].sort(reverse=True) - include_regex = r"(\+\s*\d+\s*(" + '|'.join(bonus['include']) + "))" + bonus["include"].sort(reverse=True) + include_regex = r"(\+\s*\d+\s*(" + "|".join(bonus["include"]) + "))" regex = r"(?i)((?!\)" + include_regex + exclude_regex + r"(?!\<\/b\>))" Card.bonus_regex.append(regex) @@ -117,23 +132,34 @@ class Card(object): return '"' + self.name + '"' def toString(self): - return self.name + ' ' + self.cardset + ' ' + '-'.join(self.types)\ - + ' ' + self.cost + ' ' + self.description + ' ' + self.extra + return ( + self.name + + " " + + self.cardset + + " " + + "-".join(self.types) + + " " + + self.cost + + " " + + self.description + + " " + + self.extra + ) def isType(self, what): return what in self.getType().getTypeNames() def isExpansion(self): - return self.isType('Expansion') + return self.isType("Expansion") def isEvent(self): - return self.isType('Event') + return self.isType("Event") def isLandmark(self): - return self.isType('Landmark') + return self.isType("Landmark") def isPrize(self): - return self.isType('Prize') + return self.isType("Prize") def get_total_cost(self, c): # Return a tuple that represents the total cost of card c @@ -145,8 +171,8 @@ class Card(object): if c.isLandmark(): c_cost = 999 elif not c.cost: - c_cost = 0 # if no cost, treat as 0 - elif '*' in c.cost: + c_cost = 0 # if no cost, treat as 0 + elif "*" in c.cost: c_cost = 998 # make it a really big number else: try: @@ -171,11 +197,15 @@ class Card(object): setImage = self.image else: if self.cardset_tag in Card.sets: - if 'image' in Card.sets[self.cardset_tag]: - setImage = Card.sets[self.cardset_tag]['image'] + if "image" in Card.sets[self.cardset_tag]: + setImage = Card.sets[self.cardset_tag]["image"] - if setImage is None and self.cardset_tag != 'base': - print('warning, no set image for set "{}", card "{}"'.format(self.cardset, self.name)) + if setImage is None and self.cardset_tag != "base": + print( + 'warning, no set image for set "{}", card "{}"'.format( + self.cardset, self.name + ) + ) return setImage def setTextIcon(self): @@ -184,33 +214,42 @@ class Card(object): setTextIcon = self.text_icon else: if self.cardset_tag in Card.sets: - if 'text_icon' in Card.sets[self.cardset_tag]: - setTextIcon = Card.sets[self.cardset_tag]['text_icon'] + if "text_icon" in Card.sets[self.cardset_tag]: + setTextIcon = Card.sets[self.cardset_tag]["text_icon"] - if setTextIcon is None and self.cardset != 'base': - print('warning, no set text for set "{}", card "{}"'.format(self.cardset, self.name)) + if setTextIcon is None and self.cardset != "base": + print( + 'warning, no set text for set "{}", card "{}"'.format( + self.cardset, self.name + ) + ) return setTextIcon def isBlank(self): - return self.isType('Blank') + return self.isType("Blank") class BlankCard(Card): - def __init__(self, num): - Card.__init__(self, str(num), 'extra', ('Blank',), 0) + Card.__init__(self, str(num), "extra", ("Blank",), 0) def isBlank(self): return True class CardType(object): - @staticmethod def decode_json(obj): return CardType(**obj) - def __init__(self, card_type, card_type_image, defaultCardCount=10, tabTextHeightOffset=0, tabCostHeightOffset=-1): + def __init__( + self, + card_type, + card_type_image, + defaultCardCount=10, + tabTextHeightOffset=0, + tabCostHeightOffset=-1, + ): self.typeNames = tuple(card_type) self.tabImageFile = card_type_image self.defaultCardCount = defaultCardCount diff --git a/domdiv/draw.py b/src/domdiv/draw.py similarity index 65% rename from domdiv/draw.py rename to src/domdiv/draw.py index 7f7f1de..1067a7d 100644 --- a/domdiv/draw.py +++ b/src/domdiv/draw.py @@ -20,7 +20,7 @@ from .cards import Card def split(l, n): i = 0 while i < len(l) - n: - yield l[i:i + n] + yield l[i : i + n] i += n yield l[i:] @@ -30,35 +30,58 @@ class CardPlot(object): # It goes beyond information about the general card/divider to include page specific drawing information. # It also includes helpful methods used in manipulating the object and keeping up with tab locations. - LEFT, CENTRE, RIGHT, TOP, BOTTOM = range(100, 105) # location & directional constants + LEFT, CENTRE, RIGHT, TOP, BOTTOM = range( + 100, 105 + ) # location & directional constants tabNumber = 1 # Number of different tab locations - tabIncrement = 0 # Either 1, 0, or -1. Used to select next tab. This can change if tabSerpentine. + tabIncrement = ( + 0 + ) # Either 1, 0, or -1. Used to select next tab. This can change if tabSerpentine. tabIncrementStart = 0 # Starting value of tabIncrement tabStart = 1 # The starting tab location. tabStartSide = LEFT # The starting side for the tabs - tabSerpentine = False # What to do at the end of a line of tabs. False = start over. True = reverses direction. - lineType = 'line' # Type of outline to use: line, dot, none - cardWidth = 0 # Width of just the divider, with no extra padding/spacing. NEEDS TO BE SET. - cardHeight = 0 # Height of just the divider, with no extra padding/spacing or tab. NEEDS TO BE SET. + tabSerpentine = ( + False + ) # What to do at the end of a line of tabs. False = start over. True = reverses direction. + lineType = "line" # Type of outline to use: line, dot, none + cardWidth = ( + 0 + ) # Width of just the divider, with no extra padding/spacing. NEEDS TO BE SET. + cardHeight = ( + 0 + ) # Height of just the divider, with no extra padding/spacing or tab. NEEDS TO BE SET. tabWidth = 0 # Width of the tab. NEEDS TO BE SET. tabHeight = 0 # Height of the tab. NEEDS TO BE SET. wrapper = False # If the divider is a sleeve/wrapper. @staticmethod - def tabSetup(tabNumber=None, cardWidth=None, cardHeight=None, tabWidth=None, tabHeight=None, - lineType=None, start=None, serpentine=None, wrapper=None): + def tabSetup( + tabNumber=None, + cardWidth=None, + cardHeight=None, + tabWidth=None, + tabHeight=None, + lineType=None, + start=None, + serpentine=None, + wrapper=None, + ): # Set up the basic tab information used in calculations when a new CardPlot object is created. # This needs to be called at least once before the first CardPlot object is created and then it # needs to be called any time one of the above parameters needs to change. CardPlot.tabNumber = tabNumber if tabNumber is not None else CardPlot.tabNumber CardPlot.cardWidth = cardWidth if cardWidth is not None else CardPlot.cardWidth - CardPlot.cardHeight = cardHeight if cardHeight is not None else CardPlot.cardHeight + CardPlot.cardHeight = ( + cardHeight if cardHeight is not None else CardPlot.cardHeight + ) CardPlot.tabWidth = tabWidth if tabWidth is not None else CardPlot.tabWidth CardPlot.tabHeight = tabHeight if tabHeight is not None else CardPlot.tabHeight CardPlot.lineType = lineType if lineType is not None else CardPlot.lineType CardPlot.tabStartSide = start if start is not None else CardPlot.tabStartSide - CardPlot.tabSerpentine = serpentine if serpentine is not None else CardPlot.tabSerpentine + CardPlot.tabSerpentine = ( + serpentine if serpentine is not None else CardPlot.tabSerpentine + ) CardPlot.wrapper = wrapper if wrapper is not None else CardPlot.wrapper # LEFT tabs RIGHT # +---+ +---+ +---+ +---+ +---+ @@ -89,28 +112,61 @@ class CardPlot(object): CardPlot.tabIncrement = CardPlot.tabIncrementStart return CardPlot.tabStart - def __init__(self, card, x=0, y=0, rotation=0, stackHeight=0, tabIndex=None, page=0, - textTypeFront="card", textTypeBack="rules", - cropOnTop=False, cropOnBottom=False, cropOnLeft=False, cropOnRight=False): + def __init__( + self, + card, + x=0, + y=0, + rotation=0, + stackHeight=0, + tabIndex=None, + page=0, + textTypeFront="card", + textTypeBack="rules", + cropOnTop=False, + cropOnBottom=False, + cropOnLeft=False, + cropOnRight=False, + ): self.card = card self.x = x # x location of the lower left corner of the card on the page self.y = y # y location of the lower left corner of the card on the page self.rotation = rotation # of the card. 0, 90, 180, 270 - self.stackHeight = stackHeight # The height of a stack of these cards. Used for interleaving. - self.tabIndex = tabIndex # Tab location index. Starts at 1 and goes up to CardPlot.tabNumber + self.stackHeight = ( + stackHeight + ) # The height of a stack of these cards. Used for interleaving. + self.tabIndex = ( + tabIndex + ) # Tab location index. Starts at 1 and goes up to CardPlot.tabNumber self.page = page # holds page number of this printed card - self.textTypeFront = textTypeFront # What card text to put on the front of the divider - self.textTypeBack = textTypeBack # What card text to put on the back of the divider - self.cropOnTop = cropOnTop # When true, cropmarks needed along TOP *printed* edge of the card - self.cropOnBottom = cropOnBottom # When true, cropmarks needed along BOTTOM *printed* edge of the card - self.cropOnLeft = cropOnLeft # When true, cropmarks needed along LEFT *printed* edge of the card - self.cropOnRight = cropOnRight # When true, cropmarks needed along RIGHT *printed* edge of the card + self.textTypeFront = ( + textTypeFront + ) # What card text to put on the front of the divider + self.textTypeBack = ( + textTypeBack + ) # What card text to put on the back of the divider + self.cropOnTop = ( + cropOnTop + ) # When true, cropmarks needed along TOP *printed* edge of the card + self.cropOnBottom = ( + cropOnBottom + ) # When true, cropmarks needed along BOTTOM *printed* edge of the card + self.cropOnLeft = ( + cropOnLeft + ) # When true, cropmarks needed along LEFT *printed* edge of the card + self.cropOnRight = ( + cropOnRight + ) # When true, cropmarks needed along RIGHT *printed* edge of the card # And figure out the backside index if self.tabIndex == 0: - self.tabIndexBack = 0 # Exact Centre special case, so swapping is still exact centre + self.tabIndexBack = ( + 0 + ) # Exact Centre special case, so swapping is still exact centre elif CardPlot.tabNumber == 1: - self.tabIndex = self.tabIndexBack = 1 # There is only one tab, so can only use 1 for both sides + self.tabIndex = ( + self.tabIndexBack + ) = 1 # There is only one tab, so can only use 1 for both sides elif 1 <= self.tabIndex <= CardPlot.tabNumber: self.tabIndexBack = CardPlot.tabNumber + 1 - self.tabIndex else: @@ -120,7 +176,9 @@ class CardPlot(object): # Now set the offsets and the closest edge to the tab if self.tabIndex == 0: # Special case for centred tabs - self.tabOffset = self.tabOffsetBack = (CardPlot.cardWidth - CardPlot.tabWidth) / 2 + self.tabOffset = self.tabOffsetBack = ( + CardPlot.cardWidth - CardPlot.tabWidth + ) / 2 self.closestSide = CardPlot.CENTRE elif CardPlot.tabNumber <= 1: # If just one tab, then can be right, centre, or left @@ -138,14 +196,19 @@ class CardPlot(object): else: # More than 1 tabs self.tabOffset = (self.tabIndex - 1) * ( - (CardPlot.cardWidth - CardPlot.tabWidth) / (CardPlot.tabNumber - 1)) + (CardPlot.cardWidth - CardPlot.tabWidth) / (CardPlot.tabNumber - 1) + ) self.tabOffsetBack = CardPlot.cardWidth - CardPlot.tabWidth - self.tabOffset # Set which edge is closest to the tab if self.tabIndex <= CardPlot.tabNumber / 2: self.closestSide = CardPlot.LEFT else: - self.closestSide = CardPlot.RIGHT if self.tabIndex > (CardPlot.tabNumber + 1) / 2 else CardPlot.CENTRE + self.closestSide = ( + CardPlot.RIGHT + if self.tabIndex > (CardPlot.tabNumber + 1) / 2 + else CardPlot.CENTRE + ) def setXY(self, x, y, rotation=None): # set the card to the given x,y and optional rotation @@ -210,7 +273,10 @@ class CardPlot(object): else: self.tabIndex, self.tabIndexBack = self.tabIndexBack, self.tabIndex self.tabOffset, self.tabOffsetBack = self.tabOffsetBack, self.tabOffset - self.textTypeFront, self.textTypeBack = self.textTypeBack, self.textTypeFront + self.textTypeFront, self.textTypeBack = ( + self.textTypeBack, + self.textTypeFront, + ) self.closestSide = self.getClosestSide(backside=True) def translate(self, canvas, page_width, backside=False): @@ -248,7 +314,9 @@ class CardPlot(object): else: x += height - rotation = 360 - rotation % 360 # ReportLab rotates counter clockwise, not clockwise. + rotation = ( + 360 - rotation % 360 + ) # ReportLab rotates counter clockwise, not clockwise. canvas.translate(x, y) canvas.rotate(rotation) @@ -303,15 +371,24 @@ class Plotter(object): self.canvas = canvas self.x = x self.y = y - self.LEFT, self.RIGHT, self.TOP, self.BOTTOM, self.LINE, self.NO_LINE, self.DOT = range(1, 8) # Constants + self.LEFT, self.RIGHT, self.TOP, self.BOTTOM, self.LINE, self.NO_LINE, self.DOT = range( + 1, 8 + ) # Constants if cropmarkLength < 0: cropmarkLength = 0.2 if cropmarkSpacing < 0: cropmarkSpacing = 0.1 self.CropMarkLength = cropmarkLength * cm # The length of a cropmark - self.CropMarkSpacing = cropmarkSpacing * cm # The spacing between the cut point and the start of the cropmark + self.CropMarkSpacing = ( + cropmarkSpacing * cm + ) # The spacing between the cut point and the start of the cropmark self.DotSize = 0.2 # Size of dot marks - self.CropEnable = {self.LEFT: False, self.RIGHT: False, self.TOP: False, self.BOTTOM: False} + self.CropEnable = { + self.LEFT: False, + self.RIGHT: False, + self.TOP: False, + self.BOTTOM: False, + } def setXY(self, x, y): self.x = x @@ -348,10 +425,18 @@ class Plotter(object): # 2. A direction to draw a drop mark if isinstance(mark, tuple): direction, enable = mark - enable = enable and self.CropEnable[direction] if direction in self.CropEnable else False + enable = ( + enable and self.CropEnable[direction] + if direction in self.CropEnable + else False + ) else: direction = mark - enable = self.CropEnable[direction] if direction in self.CropEnable else False + enable = ( + self.CropEnable[direction] + if direction in self.CropEnable + else False + ) if direction in self.CropEnable: self.cropmark(direction, enable) @@ -383,7 +468,7 @@ class DividerDrawer(object): @staticmethod def get_image_filepath(fname): - return pkg_resources.resource_filename('domdiv', os.path.join('images', fname)) + return pkg_resources.resource_filename("domdiv", os.path.join("images", fname)) def draw(self, cards=[], options=None): if options is not None: @@ -392,7 +477,8 @@ class DividerDrawer(object): self.registerFonts() self.canvas = canvas.Canvas( self.options.outfile, - pagesize=(self.options.paperwidth, self.options.paperheight)) + pagesize=(self.options.paperwidth, self.options.paperheight), + ) self.drawDividers(cards) if self.options.info or self.options.info_all: self.drawInfo() @@ -400,39 +486,59 @@ class DividerDrawer(object): def registerFonts(self): # the following are filenames from both an Adobe Reader install and a download from fontsgeek - fontfilenames = ['MinionPro-Regular.ttf', - 'MinionPro-Bold.ttf', - 'MinionPro-It.ttf', - 'Minion Pro Regular.ttf', - 'Minion Pro Bold.ttf', - 'Minion Pro Italic.ttf'] + fontfilenames = [ + "MinionPro-Regular.ttf", + "MinionPro-Bold.ttf", + "MinionPro-It.ttf", + "Minion Pro Regular.ttf", + "Minion Pro Bold.ttf", + "Minion Pro Italic.ttf", + ] # first figure out which, if any, are present - fontpaths = [os.path.join('fonts', fname) for fname in fontfilenames] - fontpaths = [fpath for fpath in fontpaths if pkg_resources.resource_exists('domdiv', fpath)] - self.font_mapping = {'Regular': [fpath for fpath in fontpaths if 'Regular' in fpath], - 'Bold': [fpath for fpath in fontpaths if 'Bold' in fpath], - 'Italic': [fpath for fpath in fontpaths if 'It' in fpath]} + fontpaths = [os.path.join("fonts", fname) for fname in fontfilenames] + fontpaths = [ + fpath + for fpath in fontpaths + if pkg_resources.resource_exists("domdiv", fpath) + ] + self.font_mapping = { + "Regular": [fpath for fpath in fontpaths if "Regular" in fpath], + "Bold": [fpath for fpath in fontpaths if "Bold" in fpath], + "Italic": [fpath for fpath in fontpaths if "It" in fpath], + } # then make sure that we have at least one for each type for fonttype in self.font_mapping: if not len(self.font_mapping[fonttype]): - print(("Warning, Minion Pro ttf file for {} missing from domdiv/fonts!" - " Falling back on Times font for everything.").format(fonttype), file=sys.stderr) - self.font_mapping = {'Regular': 'Times-Roman', - 'Bold': 'Times-Bold', - 'Italic': 'Times-Oblique'} + print( + ( + "Warning, Minion Pro ttf file for {} missing from domdiv/fonts!" + " Falling back on Times font for everything." + ).format(fonttype), + file=sys.stderr, + ) + self.font_mapping = { + "Regular": "Times-Roman", + "Bold": "Times-Bold", + "Italic": "Times-Oblique", + } break else: # and finally register and tag one for each type - ftag = 'MinionPro-{}'.format(fonttype) - pdfmetrics.registerFont(TTFont(ftag, - pkg_resources.resource_filename('domdiv', - self.font_mapping[fonttype][0]))) + ftag = "MinionPro-{}".format(fonttype) + pdfmetrics.registerFont( + TTFont( + ftag, + pkg_resources.resource_filename( + "domdiv", self.font_mapping[fonttype][0] + ), + ) + ) self.font_mapping[fonttype] = ftag - self.font_mapping['Monospaced'] = 'Courier' + self.font_mapping["Monospaced"] = "Courier" def drawTextPages(self, pages, margin=1.0, fontsize=10, leading=10, spacer=0.05): - s = getSampleStyleSheet()['BodyText'] - s.fontName = self.font_mapping['Monospaced'] + s = getSampleStyleSheet()["BodyText"] + s.fontName = self.font_mapping["Monospaced"] s.alignment = TA_LEFT textHorizontalMargin = margin * cm @@ -475,9 +581,9 @@ class DividerDrawer(object): # A unique separator that will not be found in any normal text. Was '@@@***!!!***@@@' at one time. sep = chr(30) + chr(31) # Generic space. Other options are ' ', ' ', ' ' - space = ' ' + space = " " tab_spaces = 4 - blank_line = (space + '\n') * 2 + blank_line = (space + "\n") * 2 if self.options.info or self.options.info_all: text = "" @@ -492,26 +598,32 @@ class DividerDrawer(object): text += "Options for this file:\n" cmd = " ".join(self.options.argv) - cmd = cmd.replace(' --', sep + '--') - cmd = cmd.replace(' -', sep + '-') - cmd = cmd.replace(sep, '\n' + space * tab_spaces) + cmd = cmd.replace(" --", sep + "--") + cmd = cmd.replace(" -", sep + "-") + cmd = cmd.replace(sep, "\n" + space * tab_spaces) text += cmd text += blank_line if printIt: - self.drawTextPages([text], margin=1.0, fontsize=10, leading=10, spacer=0.05) + self.drawTextPages( + [text], margin=1.0, fontsize=10, leading=10, spacer=0.05 + ) pageCount += 1 if self.options.info_all: linesPerPage = 80 - lines = self.options.help.replace('\n\n', blank_line).replace(' ', space).split('\n') + lines = ( + self.options.help.replace("\n\n", blank_line) + .replace(" ", space) + .split("\n") + ) pages = [] lineCount = 0 text = "" for line in lines: lineCount += 1 - text += line + '\n' + text += line + "\n" if lineCount >= linesPerPage: pages.append(text) pageCount += 1 @@ -521,12 +633,16 @@ class DividerDrawer(object): pages.append(text) pageCount += 1 if printIt: - self.drawTextPages(pages, margin=0.75, fontsize=6, leading=7, spacer=0.1) + self.drawTextPages( + pages, margin=0.75, fontsize=6, leading=7, spacer=0.1 + ) return pageCount def wantCentreTab(self, card): - return (card.isExpansion() and self.options.centre_expansion_dividers) or self.options.tab_side == "centre" + return ( + card.isExpansion() and self.options.centre_expansion_dividers + ) or self.options.tab_side == "centre" def drawOutline(self, item, isBack=False): # draw outline or cropmarks @@ -542,9 +658,11 @@ class DividerDrawer(object): self.canvas.translate(item.cardWidth, 0) self.canvas.scale(-1, 1) - plotter = Plotter(self.canvas, - cropmarkLength=self.options.cropmarkLength, - cropmarkSpacing=self.options.cropmarkSpacing) + plotter = Plotter( + self.canvas, + cropmarkLength=self.options.cropmarkLength, + cropmarkSpacing=self.options.cropmarkSpacing, + ) dividerWidth = item.cardWidth dividerHeight = item.cardHeight + item.tabHeight @@ -559,10 +677,10 @@ class DividerDrawer(object): left2tab = left2tab if left2tab > nearZero else 0 right2tab = right2tab if right2tab > nearZero else 0 - if item.lineType.lower() == 'line': + if item.lineType.lower() == "line": lineType = plotter.LINE lineTypeNoDot = plotter.LINE - elif item.lineType.lower() == 'dot': + elif item.lineType.lower() == "dot": lineType = plotter.DOT lineTypeNoDot = plotter.NO_LINE else: @@ -582,10 +700,18 @@ class DividerDrawer(object): TOP = plotter.TOP NO_LINE = plotter.NO_LINE - plotter.setCropEnable(RIGHT, self.options.cropmarks and item.translateCropmarkEnable(item.RIGHT)) - plotter.setCropEnable(LEFT, self.options.cropmarks and item.translateCropmarkEnable(item.LEFT)) - plotter.setCropEnable(TOP, self.options.cropmarks and item.translateCropmarkEnable(item.TOP)) - plotter.setCropEnable(BOTTOM, self.options.cropmarks and item.translateCropmarkEnable(item.BOTTOM)) + plotter.setCropEnable( + RIGHT, self.options.cropmarks and item.translateCropmarkEnable(item.RIGHT) + ) + plotter.setCropEnable( + LEFT, self.options.cropmarks and item.translateCropmarkEnable(item.LEFT) + ) + plotter.setCropEnable( + TOP, self.options.cropmarks and item.translateCropmarkEnable(item.TOP) + ) + plotter.setCropEnable( + BOTTOM, self.options.cropmarks and item.translateCropmarkEnable(item.BOTTOM) + ) if not item.wrapper: # Normal Card Outline @@ -601,21 +727,21 @@ class DividerDrawer(object): # A-7------------0-------------------0-------------7-B # | V| W| | # - plotter.plot(0, 0, NO_LINE, [LEFT, BOTTOM]) # ? to A - plotter.plot(left2tab, 0, lineStyle[0], BOTTOM) # A to V - plotter.plot(theTabWidth, 0, lineStyle[0], BOTTOM) # V to W + plotter.plot(0, 0, NO_LINE, [LEFT, BOTTOM]) # ? to A + plotter.plot(left2tab, 0, lineStyle[0], BOTTOM) # A to V + plotter.plot(theTabWidth, 0, lineStyle[0], BOTTOM) # V to W plotter.plot(right2tab, 0, lineStyle[7], [BOTTOM, RIGHT]) # W to B - plotter.plot(0, dividerBaseHeight, lineStyle[9], RIGHT) # B to C - plotter.plot(-right2tab, 0, lineStyle[9]) # C to D - plotter.plot(0, theTabHeight, lineStyle[7], TOP) # D to E - plotter.plot(right2tab, 0, NO_LINE, [TOP, RIGHT]) # E to Y - plotter.plot(-right2tab, 0, NO_LINE) # Y to E - plotter.plot(-theTabWidth, 0, lineStyle[7], TOP) # E to F - plotter.plot(0, -theTabHeight, lineStyle[8]) # F to G - plotter.plot(-left2tab, 0, lineStyle[8], LEFT) # G to H - plotter.plot(0, theTabHeight, NO_LINE, [TOP, LEFT]) # H to Z - plotter.plot(0, -theTabHeight, NO_LINE) # Z to H - plotter.plot(0, -dividerBaseHeight, lineStyle[7]) # H to A + plotter.plot(0, dividerBaseHeight, lineStyle[9], RIGHT) # B to C + plotter.plot(-right2tab, 0, lineStyle[9]) # C to D + plotter.plot(0, theTabHeight, lineStyle[7], TOP) # D to E + plotter.plot(right2tab, 0, NO_LINE, [TOP, RIGHT]) # E to Y + plotter.plot(-right2tab, 0, NO_LINE) # Y to E + plotter.plot(-theTabWidth, 0, lineStyle[7], TOP) # E to F + plotter.plot(0, -theTabHeight, lineStyle[8]) # F to G + plotter.plot(-left2tab, 0, lineStyle[8], LEFT) # G to H + plotter.plot(0, theTabHeight, NO_LINE, [TOP, LEFT]) # H to Z + plotter.plot(0, -theTabHeight, NO_LINE) # Z to H + plotter.plot(0, -dividerBaseHeight, lineStyle[7]) # H to A else: # Card Wrapper Outline @@ -625,7 +751,9 @@ class DividerDrawer(object): if self.options.notch_length * cm > minNotch: # A notch length was given, so notches are wanted notch_height = self.options.notch_height * cm # thumb notch height - notch1 = notch2 = notch3 = notch4 = self.options.notch_length * cm # thumb notch width + notch1 = notch2 = notch3 = notch4 = ( + self.options.notch_length * cm + ) # thumb notch width notch1used = notch2used = notch3used = notch4used = True # For now else: # No notches are wanted @@ -689,86 +817,116 @@ class DividerDrawer(object): # | | | | | | # <-----left2tab----------> <--tabLabelWidth--> <-----right2tab--------> - plotter.plot(0, 0, NO_LINE, [BOTTOM, LEFT]) # ? to A - plotter.plot(0, theTabHeight, NO_LINE, LEFT) # A to B - plotter.plot(0, notch_height, NO_LINE, (LEFT, notch4used or notch1used)) # B to GG - plotter.plot(notch4, 0, lineStyle[4]) # GG to Ca - plotter.plot(0, -notch_height, lineStyle[8]) # Ca to Cb - plotter.plot(0, -theTabHeight, NO_LINE, (BOTTOM, notch4used or notch2used)) # Cb to Cc - plotter.plot(0, theTabHeight, NO_LINE) # Cc to Cb - plotter.plot(tab2notch4, 0, lineStyle[8]) # Cb to C - plotter.plot(0, -theTabHeight, lineStyle[7], BOTTOM) # C to D - plotter.plot(tabLabelWidth, 0, lineStyle[7], BOTTOM) # D to E - plotter.plot(0, theTabHeight, lineStyle[9]) # E to F - plotter.plot(tab2notch1, 0, lineStyle[1]) # F to G - plotter.plot(0, -theTabHeight, NO_LINE, (BOTTOM, notch1used or notch3used)) # G to Ga - plotter.plot(0, theTabHeight, NO_LINE) # Ga to G - plotter.plot(0, notch_height, lineStyle[1]) # G to H - plotter.plot(notch1, 0, lineStyle[5], (RIGHT, notch1used or notch4used)) # H to I - plotter.plot(0, -notch_height, NO_LINE, RIGHT) # I to Ia - plotter.plot(0, -theTabHeight, NO_LINE, [RIGHT, BOTTOM]) # Ia to Ib - plotter.plot(0, theTabHeight, NO_LINE) # Ib to Ia - plotter.plot(0, notch_height, NO_LINE) # Ia to I - plotter.plot(0, body_minus_notches, lineStyle[3], (RIGHT, notch2used or notch3used)) # I to J - plotter.plot(-notch3, 0, lineStyle[3]) # J to K - plotter.plot(0, notch_height, lineStyle[0]) # K to L - plotter.plot(0, stackHeight, lineStyle[0]) # L to M - plotter.plot(0, notch_height, lineStyle[3]) # M to N - plotter.plot(notch3, 0, lineStyle[3], (RIGHT, notch2used or notch3used)) # N to O - plotter.plot(0, body_minus_notches, lineStyle[5], (RIGHT, notch1used or notch4used)) # O to P - plotter.plot(0, notch_height, NO_LINE, RIGHT) # P to Pa - plotter.plot(0, -notch_height, NO_LINE) # Pa to P - plotter.plot(-notch1, 0, lineStyle[1]) # P to Q - plotter.plot(0, notch_height, lineStyle[9]) # Q to R - plotter.plot(-tab2notch1, 0, lineStyle[9]) # R to S - plotter.plot(0, stackHeight, lineStyle[0]) # S to T - plotter.plot(0, theTabHeight, lineStyle[7], TOP) # S to U - plotter.plot(tab2notch1, 0, NO_LINE, (TOP, notch1used or notch3used)) # U to Ua - plotter.plot(notch1, 0, NO_LINE, [TOP, RIGHT]) # Ua to Ub - plotter.plot(-notch1, 0, NO_LINE) # Ub to Ua - plotter.plot(-tab2notch1, 0, NO_LINE) # Ua to U - plotter.plot(-theTabWidth, 0, lineStyle[7], TOP) # U to V - plotter.plot(-tab2notch4, 0, NO_LINE, (TOP, notch4used or notch2used)) # V to Va - plotter.plot(tab2notch4, 0, NO_LINE) # Va to V - plotter.plot(0, -theTabHeight, lineStyle[0]) # V to W - plotter.plot(0, -stackHeight, lineStyle[8]) # W to X - plotter.plot(-tab2notch4, 0, lineStyle[8]) # X to Y - plotter.plot(0, -notch_height, lineStyle[4]) # Y to Ya - plotter.plot(-notch4, 0, lineStyle[6], (LEFT, notch1used or notch4used)) # Ya to Z - plotter.plot(0, notch_height, NO_LINE, LEFT) # Z to Za - plotter.plot(0, theTabHeight + stackHeight, NO_LINE, [TOP, LEFT]) # Za to Zb - plotter.plot(0, -theTabHeight - stackHeight, NO_LINE) # Zb to Za - plotter.plot(0, -notch_height, NO_LINE) # Za to Z - plotter.plot(0, -body_minus_notches, lineStyle[2], (LEFT, notch2used or notch3used)) # Z to AA - plotter.plot(notch2, 0, lineStyle[2]) # AA to BB - plotter.plot(0, -notch_height, lineStyle[0]) # BB to CC - plotter.plot(0, -stackHeight, lineStyle[0]) # CC to DD - plotter.plot(0, -notch_height, lineStyle[2]) # DD to EE - plotter.plot(-notch2, 0, lineStyle[2], (LEFT, notch2used or notch3used)) # EE to FF - plotter.plot(0, -body_minus_notches, lineStyle[6]) # FF to GG + plotter.plot(0, 0, NO_LINE, [BOTTOM, LEFT]) # ? to A + plotter.plot(0, theTabHeight, NO_LINE, LEFT) # A to B + plotter.plot( + 0, notch_height, NO_LINE, (LEFT, notch4used or notch1used) + ) # B to GG + plotter.plot(notch4, 0, lineStyle[4]) # GG to Ca + plotter.plot(0, -notch_height, lineStyle[8]) # Ca to Cb + plotter.plot( + 0, -theTabHeight, NO_LINE, (BOTTOM, notch4used or notch2used) + ) # Cb to Cc + plotter.plot(0, theTabHeight, NO_LINE) # Cc to Cb + plotter.plot(tab2notch4, 0, lineStyle[8]) # Cb to C + plotter.plot(0, -theTabHeight, lineStyle[7], BOTTOM) # C to D + plotter.plot(tabLabelWidth, 0, lineStyle[7], BOTTOM) # D to E + plotter.plot(0, theTabHeight, lineStyle[9]) # E to F + plotter.plot(tab2notch1, 0, lineStyle[1]) # F to G + plotter.plot( + 0, -theTabHeight, NO_LINE, (BOTTOM, notch1used or notch3used) + ) # G to Ga + plotter.plot(0, theTabHeight, NO_LINE) # Ga to G + plotter.plot(0, notch_height, lineStyle[1]) # G to H + plotter.plot( + notch1, 0, lineStyle[5], (RIGHT, notch1used or notch4used) + ) # H to I + plotter.plot(0, -notch_height, NO_LINE, RIGHT) # I to Ia + plotter.plot(0, -theTabHeight, NO_LINE, [RIGHT, BOTTOM]) # Ia to Ib + plotter.plot(0, theTabHeight, NO_LINE) # Ib to Ia + plotter.plot(0, notch_height, NO_LINE) # Ia to I + plotter.plot( + 0, body_minus_notches, lineStyle[3], (RIGHT, notch2used or notch3used) + ) # I to J + plotter.plot(-notch3, 0, lineStyle[3]) # J to K + plotter.plot(0, notch_height, lineStyle[0]) # K to L + plotter.plot(0, stackHeight, lineStyle[0]) # L to M + plotter.plot(0, notch_height, lineStyle[3]) # M to N + plotter.plot( + notch3, 0, lineStyle[3], (RIGHT, notch2used or notch3used) + ) # N to O + plotter.plot( + 0, body_minus_notches, lineStyle[5], (RIGHT, notch1used or notch4used) + ) # O to P + plotter.plot(0, notch_height, NO_LINE, RIGHT) # P to Pa + plotter.plot(0, -notch_height, NO_LINE) # Pa to P + plotter.plot(-notch1, 0, lineStyle[1]) # P to Q + plotter.plot(0, notch_height, lineStyle[9]) # Q to R + plotter.plot(-tab2notch1, 0, lineStyle[9]) # R to S + plotter.plot(0, stackHeight, lineStyle[0]) # S to T + plotter.plot(0, theTabHeight, lineStyle[7], TOP) # S to U + plotter.plot( + tab2notch1, 0, NO_LINE, (TOP, notch1used or notch3used) + ) # U to Ua + plotter.plot(notch1, 0, NO_LINE, [TOP, RIGHT]) # Ua to Ub + plotter.plot(-notch1, 0, NO_LINE) # Ub to Ua + plotter.plot(-tab2notch1, 0, NO_LINE) # Ua to U + plotter.plot(-theTabWidth, 0, lineStyle[7], TOP) # U to V + plotter.plot( + -tab2notch4, 0, NO_LINE, (TOP, notch4used or notch2used) + ) # V to Va + plotter.plot(tab2notch4, 0, NO_LINE) # Va to V + plotter.plot(0, -theTabHeight, lineStyle[0]) # V to W + plotter.plot(0, -stackHeight, lineStyle[8]) # W to X + plotter.plot(-tab2notch4, 0, lineStyle[8]) # X to Y + plotter.plot(0, -notch_height, lineStyle[4]) # Y to Ya + plotter.plot( + -notch4, 0, lineStyle[6], (LEFT, notch1used or notch4used) + ) # Ya to Z + plotter.plot(0, notch_height, NO_LINE, LEFT) # Z to Za + plotter.plot( + 0, theTabHeight + stackHeight, NO_LINE, [TOP, LEFT] + ) # Za to Zb + plotter.plot(0, -theTabHeight - stackHeight, NO_LINE) # Zb to Za + plotter.plot(0, -notch_height, NO_LINE) # Za to Z + plotter.plot( + 0, -body_minus_notches, lineStyle[2], (LEFT, notch2used or notch3used) + ) # Z to AA + plotter.plot(notch2, 0, lineStyle[2]) # AA to BB + plotter.plot(0, -notch_height, lineStyle[0]) # BB to CC + plotter.plot(0, -stackHeight, lineStyle[0]) # CC to DD + plotter.plot(0, -notch_height, lineStyle[2]) # DD to EE + plotter.plot( + -notch2, 0, lineStyle[2], (LEFT, notch2used or notch3used) + ) # EE to FF + plotter.plot(0, -body_minus_notches, lineStyle[6]) # FF to GG # Add fold lines self.canvas.setStrokeGray(0.9) - plotter.setXY(left2tab, dividerHeight + stackHeight + dividerBaseHeight) # ? to X - plotter.plot(theTabWidth, 0, plotter.LINE) # X to S - plotter.plot(0, stackHeight) # S to T - plotter.plot(-theTabWidth, 0, plotter.LINE) # V to S + plotter.setXY( + left2tab, dividerHeight + stackHeight + dividerBaseHeight + ) # ? to X + plotter.plot(theTabWidth, 0, plotter.LINE) # X to S + plotter.plot(0, stackHeight) # S to T + plotter.plot(-theTabWidth, 0, plotter.LINE) # V to S - plotter.setXY(notch2, dividerHeight) # ? to DD - plotter.plot(dividerWidth - notch2 - notch3, 0, plotter.LINE) # DD to L - plotter.plot(0, stackHeight) # L to M - plotter.plot(-dividerWidth + notch2 + notch3, 0, plotter.LINE) # M to CC + plotter.setXY(notch2, dividerHeight) # ? to DD + plotter.plot(dividerWidth - notch2 - notch3, 0, plotter.LINE) # DD to L + plotter.plot(0, stackHeight) # L to M + plotter.plot(-dividerWidth + notch2 + notch3, 0, plotter.LINE) # M to CC self.canvas.restoreState() def add_inline_images(self, text, fontsize): - def replace_image_tag(text, - fontsize, - tag_pattern, - fname_replace, - fontsize_multiplier, - height_percent, - text_fontsize_multiplier=None): + def replace_image_tag( + text, + fontsize, + tag_pattern, + fname_replace, + fontsize_multiplier, + height_percent, + text_fontsize_multiplier=None, + ): replace_template = '' offset = 0 for match in re.finditer(tag_pattern, text): @@ -776,36 +934,43 @@ class DividerDrawer(object): tag = match.group(0) fname = re.sub(tag_pattern, fname_replace, tag) if text_fontsize_multiplier is not None: - font_replace = re.sub(tag_pattern, - '\\1'.format(fontsize * text_fontsize_multiplier), - tag) + font_replace = re.sub( + tag_pattern, + "\\1".format( + fontsize * text_fontsize_multiplier + ), + tag, + ) replace = font_replace + replace - replace = replace.format(fpath=DividerDrawer.get_image_filepath(fname), - width=fontsize * fontsize_multiplier, - height_percent=height_percent) - text = text[:match.start() + offset] + replace + text[match.end() + offset:] + replace = replace.format( + fpath=DividerDrawer.get_image_filepath(fname), + width=fontsize * fontsize_multiplier, + height_percent=height_percent, + ) + text = ( + text[: match.start() + offset] + + replace + + text[match.end() + offset :] + ) offset += len(replace) - len(match.group(0)) return text + # Coins replace_specs = [ # Coins - (r'(\d+)\s\<\*COIN\*\>', 'coin_small_\\1.png', 2.4, 200), - (r'(\d+)\s(c|C)oin(s)?', 'coin_small_\\1.png', 1.2, 100), - (r'\?\s(c|C)oin(s)?', 'coin_small_question.png', 1.2, 100), - (r'(empty|\_)\s(c|C)oin(s)?', 'coin_small_empty.png', 1.2, 100), - + (r"(\d+)\s\<\*COIN\*\>", "coin_small_\\1.png", 2.4, 200), + (r"(\d+)\s(c|C)oin(s)?", "coin_small_\\1.png", 1.2, 100), + (r"\?\s(c|C)oin(s)?", "coin_small_question.png", 1.2, 100), + (r"(empty|\_)\s(c|C)oin(s)?", "coin_small_empty.png", 1.2, 100), # VP - (r'(?:\s+|\<)VP(?:\s+|\>|\.|$)', 'victory_emblem.png', 1.25, 100), - (r'(\d+)\s*\<\*VP\*\>', 'victory_emblem.png', 2, 160, 1.3), - + (r"(?:\s+|\<)VP(?:\s+|\>|\.|$)", "victory_emblem.png", 1.25, 100), + (r"(\d+)\s*\<\*VP\*\>", "victory_emblem.png", 2, 160, 1.3), # Debt - (r'(\d+)\sDebt', 'debt_\\1.png', 1.2, 105), - (r'Debt', 'debt.png', 1.2, 105), - + (r"(\d+)\sDebt", "debt_\\1.png", 1.2, 105), + (r"Debt", "debt.png", 1.2, 105), # Potion - (r'(\d+)\s*\<\*POTION\*\>', 'potion_small.png', 2, 140, 1.5), - (r'Potion', 'potion_small.png', 1.2, 100) - + (r"(\d+)\s*\<\*POTION\*\>", "potion_small.png", 2, 140, 1.5), + (r"Potion", "potion_small.png", 1.2, 100), ] for args in replace_specs: text = replace_image_tag(text, fontsize, *args) @@ -820,8 +985,8 @@ class DividerDrawer(object): replace = "
{}
\n".format("–" * 22) text = re.sub(r"\", replace, text) # and \t - text = re.sub(r"\", '\t', text) - text = re.sub(r"\", '\t', text) + text = re.sub(r"\", "\t", text) + text = re.sub(r"\", "\t", text) text = re.sub(r"\t", " " * 4, text) # various breaks @@ -849,7 +1014,7 @@ class DividerDrawer(object): text = re.sub(r"\", "", text) text = re.sub(r"\", "
", text) - return text.strip().strip('\n') + return text.strip().strip("\n") def drawCardCount(self, card, x, y, offset=-1): # Note that this is right justified. @@ -869,24 +1034,27 @@ class DividerDrawer(object): width += 16 x -= 16 self.canvas.drawImage( - DividerDrawer.get_image_filepath('card.png'), + DividerDrawer.get_image_filepath("card.png"), x, countHeight, 16, 16, preserveAspectRatio=True, - mask='auto') - self.canvas.setFont(self.font_mapping['Bold'], 10) + mask="auto", + ) + self.canvas.setFont(self.font_mapping["Bold"], 10) self.canvas.drawCentredString(x + 8, countHeight + 4, str(value)) # now draw the number of sets if count > 1: count_string = u"{}\u00d7".format(count) - width_string = stringWidth(count_string, self.font_mapping['Regular'], 10) + width_string = stringWidth( + count_string, self.font_mapping["Regular"], 10 + ) width_string -= 1 # adjust to make it closer to image width += width_string x -= width_string - self.canvas.setFont(self.font_mapping['Regular'], 10) + self.canvas.setFont(self.font_mapping["Regular"], 10) self.canvas.drawString(x, countHeight + 4, count_string) return width + 1 @@ -900,19 +1068,22 @@ class DividerDrawer(object): potHeight = y - 3 potSize = 11 - if (not(card.cost == "" or - (card.debtcost and int(card.cost) == 0) or - (card.potcost and int(card.cost) == 0))): + if not ( + card.cost == "" + or (card.debtcost and int(card.cost) == 0) + or (card.potcost and int(card.cost) == 0) + ): self.canvas.drawImage( - DividerDrawer.get_image_filepath('coin_small.png'), + DividerDrawer.get_image_filepath("coin_small.png"), x, coinHeight, 16, 16, preserveAspectRatio=True, - mask='auto') - self.canvas.setFont(self.font_mapping['Bold'], 12) + mask="auto", + ) + self.canvas.setFont(self.font_mapping["Bold"], 12) self.canvas.drawCentredString(x + 8, costHeight, str(card.cost)) self.canvas.setFillColorRGB(0, 0, 0) x += 17 @@ -920,15 +1091,16 @@ class DividerDrawer(object): if card.debtcost: self.canvas.drawImage( - DividerDrawer.get_image_filepath('debt.png'), + DividerDrawer.get_image_filepath("debt.png"), x, coinHeight, 16, 16, preserveAspectRatio=True, - mask=[170, 255, 170, 255, 170, 255]) + mask=[170, 255, 170, 255, 170, 255], + ) self.canvas.setFillColorRGB(1, 1, 1) - self.canvas.setFont(self.font_mapping['Bold'], 12) + self.canvas.setFont(self.font_mapping["Bold"], 12) self.canvas.drawCentredString(x + 8, costHeight, str(card.debtcost)) self.canvas.setFillColorRGB(0, 0, 0) x += 17 @@ -936,13 +1108,14 @@ class DividerDrawer(object): if card.potcost: self.canvas.drawImage( - DividerDrawer.get_image_filepath('potion.png'), + DividerDrawer.get_image_filepath("potion.png"), x, potHeight, potSize, potSize, preserveAspectRatio=True, - mask='auto') + mask="auto", + ) width += potSize return width @@ -951,12 +1124,8 @@ class DividerDrawer(object): # set image w = 2 self.canvas.drawImage( - DividerDrawer.get_image_filepath(setImage), - x, - y, - 14, - 12, - mask='auto') + DividerDrawer.get_image_filepath(setImage), x, y, 14, 12, mask="auto" + ) return w + 14 def nameWidth(self, name, fontSize): @@ -964,12 +1133,11 @@ class DividerDrawer(object): name_parts = name.split() for i, part in enumerate(name_parts): if i != 0: - w += pdfmetrics.stringWidth(' ', self.font_mapping['Regular'], - fontSize) - w += pdfmetrics.stringWidth(part[0], self.font_mapping['Regular'], - fontSize) - w += pdfmetrics.stringWidth(part[1:], self.font_mapping['Regular'], - fontSize - 2) + w += pdfmetrics.stringWidth(" ", self.font_mapping["Regular"], fontSize) + w += pdfmetrics.stringWidth(part[0], self.font_mapping["Regular"], fontSize) + w += pdfmetrics.stringWidth( + part[1:], self.font_mapping["Regular"], fontSize - 2 + ) return w def drawTab(self, item, wrapper="no", backside=False): @@ -995,7 +1163,9 @@ class DividerDrawer(object): translate_x = item.getTabOffset(backside=False) + item.tabWidth if wrapper == "front": - translate_y = translate_y + item.cardHeight + item.tabHeight + 2.0 * item.stackHeight + translate_y = ( + translate_y + item.cardHeight + item.tabHeight + 2.0 * item.stackHeight + ) self.canvas.translate(translate_x, translate_y) @@ -1013,8 +1183,9 @@ class DividerDrawer(object): textHeight = 7 if self.options.no_tab_artwork: textHeight = 4 - textHeight = item.tabHeight / 2 - textHeight + \ - card.getType().getTabTextHeightOffset() + textHeight = ( + item.tabHeight / 2 - textHeight + card.getType().getTabTextHeightOffset() + ) # draw banner img = card.getType().getTabImageFile() @@ -1026,17 +1197,22 @@ class DividerDrawer(object): item.tabWidth - 2, item.tabHeight - 1, preserveAspectRatio=False, - anchor='n', - mask='auto') + anchor="n", + mask="auto", + ) # draw cost - if not card.isExpansion() and not card.isBlank( - ) and not card.isLandmark() and not card.isType('Trash'): - if 'tab' in self.options.cost: + if ( + not card.isExpansion() + and not card.isBlank() + and not card.isLandmark() + and not card.isType("Trash") + ): + if "tab" in self.options.cost: textInset = 4 textInset += self.drawCost( - card, textInset, textHeight, - card.getType().getTabCostHeightOffset()) + card, textInset, textHeight, card.getType().getTabCostHeightOffset() + ) else: textInset = 6 else: @@ -1049,20 +1225,18 @@ class DividerDrawer(object): if self.options.use_text_set_icon: setImageHeight = card.getType().getTabTextHeightOffset() setText = card.setTextIcon() - self.canvas.setFont(self.font_mapping['Italic'], 8) + self.canvas.setFont(self.font_mapping["Italic"], 8) if setText is None: setText = "" - self.canvas.drawCentredString(item.tabWidth - 10, - textHeight + 2, setText) + self.canvas.drawCentredString(item.tabWidth - 10, textHeight + 2, setText) textInsetRight = 15 else: setImage = card.setImage() - if setImage and 'tab' in self.options.set_icon: + if setImage and "tab" in self.options.set_icon: setImageHeight = 3 + card.getType().getTabTextHeightOffset() - self.drawSetIcon(setImage, item.tabWidth - 20, - setImageHeight) + self.drawSetIcon(setImage, item.tabWidth - 20, setImageHeight) textInsetRight = 20 @@ -1075,13 +1249,13 @@ class DividerDrawer(object): width = self.nameWidth(name, fontSize) while width > textWidth and fontSize > 8: - fontSize -= .01 + fontSize -= 0.01 width = self.nameWidth(name, fontSize) tooLong = width > textWidth if tooLong: - name_lines = name.partition(' / ') + name_lines = name.partition(" / ") if name_lines[1]: - name_lines = (name_lines[0] + ' /', name_lines[2]) + name_lines = (name_lines[0] + " /", name_lines[2]) else: name_lines = name.split(None, 1) else: @@ -1096,31 +1270,37 @@ class DividerDrawer(object): h -= h / 2 words = line.split() - NotRightEdge = ( - not self.options.tab_name_align == "right" and - (self.options.tab_name_align == "centre" or - item.getClosestSide(backside=backside) != CardPlot.RIGHT or - not self.options.tab_name_align == "edge")) + NotRightEdge = not self.options.tab_name_align == "right" and ( + self.options.tab_name_align == "centre" + or item.getClosestSide(backside=backside) != CardPlot.RIGHT + or not self.options.tab_name_align == "edge" + ) if wrapper == "back" and not self.options.tab_name_align == "centre": NotRightEdge = not NotRightEdge if NotRightEdge: - if (self.options.tab_name_align == "centre" or self.wantCentreTab(card) - or (item.getClosestSide(backside=backside) == CardPlot.CENTRE - and self.options.tab_name_align == "edge")): + if ( + self.options.tab_name_align == "centre" + or self.wantCentreTab(card) + or ( + item.getClosestSide(backside=backside) == CardPlot.CENTRE + and self.options.tab_name_align == "edge" + ) + ): w = item.tabWidth / 2 - self.nameWidth(line, fontSize) / 2 else: w = textInset def drawWordPiece(text, fontSize): - self.canvas.setFont(self.font_mapping['Regular'], fontSize) - if text != ' ': + self.canvas.setFont(self.font_mapping["Regular"], fontSize) + if text != " ": self.canvas.drawString(w, h, text) - return pdfmetrics.stringWidth(text, self.font_mapping['Regular'], - fontSize) + return pdfmetrics.stringWidth( + text, self.font_mapping["Regular"], fontSize + ) for i, word in enumerate(words): if i != 0: - w += drawWordPiece(' ', fontSize) + w += drawWordPiece(" ", fontSize) w += drawWordPiece(word[0], fontSize) w += drawWordPiece(word[1:], fontSize - 2) else: @@ -1138,23 +1318,26 @@ class DividerDrawer(object): words.reverse() def drawWordPiece(text, fontSize): - self.canvas.setFont(self.font_mapping['Regular'], fontSize) - if text != ' ': + self.canvas.setFont(self.font_mapping["Regular"], fontSize) + if text != " ": self.canvas.drawRightString(w, h, text) - return -pdfmetrics.stringWidth(text, self.font_mapping['Regular'], - fontSize) + return -pdfmetrics.stringWidth( + text, self.font_mapping["Regular"], fontSize + ) for i, word in enumerate(words): w += drawWordPiece(word[1:], fontSize - 2) w += drawWordPiece(word[0], fontSize) if i != len(words) - 1: - w += drawWordPiece(' ', fontSize) + w += drawWordPiece(" ", fontSize) if wrapper == "front" and card.getCardCount() >= 5: # Print smaller version of name on the top wrapper edge - self.canvas.translate(0, -item.stackHeight) # move into area used by the wrapper + self.canvas.translate( + 0, -item.stackHeight + ) # move into area used by the wrapper fontSize = 8 # use the smallest font - self.canvas.setFont(self.font_mapping['Regular'], fontSize) + self.canvas.setFont(self.font_mapping["Regular"], fontSize) textHeight = fontSize - 2 textHeight = item.stackHeight / 2 - textHeight / 2 @@ -1163,15 +1346,16 @@ class DividerDrawer(object): w = item.tabWidth / 2 - self.nameWidth(name, fontSize) / 2 def drawWordPiece(text, fontSize): - self.canvas.setFont(self.font_mapping['Regular'], fontSize) - if text != ' ': + self.canvas.setFont(self.font_mapping["Regular"], fontSize) + if text != " ": self.canvas.drawString(w, h, text) - return pdfmetrics.stringWidth(text, self.font_mapping['Regular'], - fontSize) + return pdfmetrics.stringWidth( + text, self.font_mapping["Regular"], fontSize + ) for i, word in enumerate(words): if i != 0: - w += drawWordPiece(' ', fontSize) + w += drawWordPiece(" ", fontSize) w += drawWordPiece(word[0], fontSize) w += drawWordPiece(word[1:], fontSize - 2) @@ -1193,7 +1377,9 @@ class DividerDrawer(object): self.canvas.rotate(180) if wrapper == "front": - self.canvas.translate(0, item.cardHeight + item.tabHeight + item.stackHeight) + self.canvas.translate( + 0, item.cardHeight + item.tabHeight + item.stackHeight + ) if wrapper == "front" or wrapper == "back": if self.options.notch_length > 0: @@ -1202,25 +1388,29 @@ class DividerDrawer(object): # Add 'body-top' items drewTopIcon = False Image_x_left = 4 - if 'body-top' in self.options.cost and not card.isExpansion(): - Image_x_left += self.drawCost(card, Image_x_left, totalHeight - usedHeight - 0.5 * cm) + if "body-top" in self.options.cost and not card.isExpansion(): + Image_x_left += self.drawCost( + card, Image_x_left, totalHeight - usedHeight - 0.5 * cm + ) drewTopIcon = True Image_x_right = item.cardWidth - 4 - if 'body-top' in self.options.set_icon and not card.isExpansion(): + if "body-top" in self.options.set_icon and not card.isExpansion(): setImage = card.setImage() if setImage: Image_x_right -= 16 - self.drawSetIcon(setImage, Image_x_right, - totalHeight - usedHeight - 0.5 * cm - 3) + self.drawSetIcon( + setImage, Image_x_right, totalHeight - usedHeight - 0.5 * cm - 3 + ) drewTopIcon = True if self.options.count: - Image_x_right -= self.drawCardCount(card, Image_x_right, - totalHeight - usedHeight - 0.5 * cm) + Image_x_right -= self.drawCardCount( + card, Image_x_right, totalHeight - usedHeight - 0.5 * cm + ) drewTopIcon = True - if (self.options.types and not card.isExpansion()): + if self.options.types and not card.isExpansion(): # Calculate how much width have for printing # Want centered, but number of other items can limit @@ -1236,21 +1426,23 @@ class DividerDrawer(object): # use all the available space, even if it is not centered on the card fontSize = 8 failover = False - width = stringWidth(card.types_name, self.font_mapping['Regular'], fontSize) + width = stringWidth(card.types_name, self.font_mapping["Regular"], fontSize) while width > textWidth: - fontSize -= .01 + fontSize -= 0.01 if fontSize < 6 and not failover: # Start over using all available space left on line textWidth = textWidth2 w = left_margin + (textWidth2 / 2) fontSize = 8 failover = True - width = stringWidth(card.types_name, self.font_mapping['Regular'], fontSize) + width = stringWidth( + card.types_name, self.font_mapping["Regular"], fontSize + ) # Print out the text in the right spot h = totalHeight - usedHeight - 0.5 * cm - self.canvas.setFont(self.font_mapping['Regular'], fontSize) - if card.types_name != ' ': + self.canvas.setFont(self.font_mapping["Regular"], fontSize) + if card.types_name != " ": self.canvas.drawCentredString(w, h, card.types_name) drewTopIcon = True @@ -1271,15 +1463,15 @@ class DividerDrawer(object): self.canvas.restoreState() return - s = getSampleStyleSheet()['BodyText'] + s = getSampleStyleSheet()["BodyText"] s.fontName = "Times-Roman" if divider_text == "card" and not card.isExpansion(): s.alignment = TA_CENTER else: s.alignment = TA_JUSTIFY - textHorizontalMargin = .5 * cm - textVerticalMargin = .3 * cm + textHorizontalMargin = 0.5 * cm + textVerticalMargin = 0.3 * cm textBoxWidth = item.cardWidth - 2 * textHorizontalMargin textBoxHeight = totalHeight - usedHeight - 2 * textVerticalMargin spacerHeight = 0.2 * cm @@ -1300,7 +1492,11 @@ class DividerDrawer(object): try: p = Paragraph(dmod, s) except ValueError as e: - raise ValueError(u'Error rendering text from "{}": {} ("{}")'.format(card.name, e, dmod)) + raise ValueError( + u'Error rendering text from "{}": {} ("{}")'.format( + card.name, e, dmod + ) + ) h += p.wrap(textBoxWidth, textBoxHeight)[1] paragraphs.append(p) @@ -1334,8 +1530,9 @@ class DividerDrawer(object): pageWidth = self.options.paperwidth - (2 * horizontalMargin) self.canvas.translate(horizontalMargin, verticalMargin) if isBack: - self.canvas.translate(self.options.back_offset, - self.options.back_offset_height) + self.canvas.translate( + self.options.back_offset, self.options.back_offset_height + ) pageWidth -= 2 * self.options.back_offset item.translate(self.canvas, pageWidth, isBack) @@ -1372,25 +1569,31 @@ class DividerDrawer(object): # calculate the text height, font size, and orientation maxFontsize = 12 minFontsize = 6 - fontname = self.font_mapping['Regular'] + fontname = self.font_mapping["Regular"] font = pdfmetrics.getFont(fontname) - fontHeightRelative = ( - font.face.ascent + abs(font.face.descent)) / 1000.0 + fontHeightRelative = (font.face.ascent + abs(font.face.descent)) / 1000.0 canFit = False - layouts = [{'rotation': 0, - 'minMarginHeight': self.options.minVerticalMargin, - 'totalMarginHeight': self.options.verticalMargin, - 'width': self.options.paperwidth}, - {'rotation': 90, - 'minMarginHeight': self.options.minHorizontalMargin, - 'totalMarginHeight': self.options.horizontalMargin, - 'width': self.options.paperheight}] + layouts = [ + { + "rotation": 0, + "minMarginHeight": self.options.minVerticalMargin, + "totalMarginHeight": self.options.verticalMargin, + "width": self.options.paperwidth, + }, + { + "rotation": 90, + "minMarginHeight": self.options.minHorizontalMargin, + "totalMarginHeight": self.options.horizontalMargin, + "width": self.options.paperheight, + }, + ] for layout in layouts: - availableMargin = layout['totalMarginHeight'] - layout[ - 'minMarginHeight'] + availableMargin = ( + layout["totalMarginHeight"] - layout["minMarginHeight"] + ) fontsize = availableMargin / fontHeightRelative fontsize = min(maxFontsize, fontsize) if fontsize >= minFontsize: @@ -1399,14 +1602,15 @@ class DividerDrawer(object): if not canFit: import warnings + warnings.warn("Not enough space to display set names") return self.canvas.setFont(fontname, fontsize) - xPos = layout['width'] / 2 + xPos = layout["width"] / 2 # Place at the very edge of the margin - yPos = layout['minMarginHeight'] + yPos = layout["minMarginHeight"] sets = [] for item in pageItems: @@ -1415,15 +1619,15 @@ class DividerDrawer(object): sets.append(setTitle) # Centered on page - xPos = layout['width'] / 2 + xPos = layout["width"] / 2 # Place at the very edge of the margin - yPos = layout['minMarginHeight'] + yPos = layout["minMarginHeight"] - if layout['rotation']: - self.canvas.rotate(layout['rotation']) + if layout["rotation"]: + self.canvas.rotate(layout["rotation"]) yPos = -yPos - self.canvas.drawCentredString(xPos, yPos, '/'.join(sets)) + self.canvas.drawCentredString(xPos, yPos, "/".join(sets)) finally: self.canvas.restoreState() @@ -1432,26 +1636,44 @@ class DividerDrawer(object): # Adjust for Vertical vs Horizontal if options.orientation == "vertical": - options.dividerWidth, options.dividerBaseHeight = options.dominionCardHeight, options.dominionCardWidth + options.dividerWidth, options.dividerBaseHeight = ( + options.dominionCardHeight, + options.dominionCardWidth, + ) else: - options.dividerWidth, options.dividerBaseHeight = options.dominionCardWidth, options.dominionCardHeight + options.dividerWidth, options.dividerBaseHeight = ( + options.dominionCardWidth, + options.dominionCardHeight, + ) options.fixedMargins = False options.spin = 0 - options.label = options.label if 'label' in options else None + options.label = options.label if "label" in options else None if options.label is not None: # Set Margins - options.minmarginheight = (options.label['margin-top'] + options.label['pad-vertical']) * cm - options.minmarginwidth = (options.label['margin-left'] + options.label['pad-horizontal']) * cm + options.minmarginheight = ( + options.label["margin-top"] + options.label["pad-vertical"] + ) * cm + options.minmarginwidth = ( + options.label["margin-left"] + options.label["pad-horizontal"] + ) * cm # Set Label size - options.labelHeight = (options.label['tab-height'] - 2 * options.label['pad-vertical']) * cm - options.labelWidth = (options.label['width'] - 2 * options.label['pad-horizontal']) * cm + options.labelHeight = ( + options.label["tab-height"] - 2 * options.label["pad-vertical"] + ) * cm + options.labelWidth = ( + options.label["width"] - 2 * options.label["pad-horizontal"] + ) * cm # Set spacing between labels - options.verticalBorderSpace = (options.label['gap-vertical'] + 2 * options.label['pad-vertical']) * cm - options.horizontalBorderSpace = (options.label['gap-horizontal'] + 2 * options.label['pad-horizontal']) * cm + options.verticalBorderSpace = ( + options.label["gap-vertical"] + 2 * options.label["pad-vertical"] + ) * cm + options.horizontalBorderSpace = ( + options.label["gap-horizontal"] + 2 * options.label["pad-horizontal"] + ) * cm # Fix up other settings options.fixedMargins = True - options.dividerBaseHeight = options.label['body-height'] * cm + options.dividerBaseHeight = options.label["body-height"] * cm options.dividerWidth = options.labelWidth options.rotate = 0 options.dominionCardWidth = options.dividerWidth @@ -1463,12 +1685,18 @@ class DividerDrawer(object): # This 'spins' the divider only, but keeps all the other calcuations the same. options.spin = 270 # Now fix up the card dimentions. - options.dominionCardWidth = options.labelHeight + options.label['body-height'] * cm - options.dominionCardHeight = options.labelWidth - options.label['tab-height'] * cm + options.dominionCardWidth = ( + options.labelHeight + options.label["body-height"] * cm + ) + options.dominionCardHeight = ( + options.labelWidth - options.label["tab-height"] * cm + ) options.labelWidth = options.dominionCardWidth # Need to swap now because they will be swapped again later because "vertical" - options.dominionCardWidth, options.dominionCardHeight = (options.dominionCardHeight, - options.dominionCardWidth) + options.dominionCardWidth, options.dominionCardHeight = ( + options.dominionCardHeight, + options.dominionCardWidth, + ) # Fix up the label dimentions if options.tab_side != "full": @@ -1477,7 +1705,7 @@ class DividerDrawer(object): else: # Margins already set # Set Label size - options.labelHeight = .9 * cm + options.labelHeight = 0.9 * cm options.labelWidth = options.tabwidth * cm if options.tab_side == "full" or options.labelWidth > options.dividerWidth: options.labelWidth = options.dividerWidth @@ -1495,15 +1723,22 @@ class DividerDrawer(object): if options.wrapper: # Adjust height for wrapper. Use the maximum thickness of any divider so we know anything will fit. maxStackHeight = max(c.getStackHeight(options.thickness) for c in cards) - options.dividerHeightReserved = 2 * (options.dividerHeightReserved + maxStackHeight) - print("Max Card Stack Height: {:.2f}cm ".format(maxStackHeight/10.0)) + options.dividerHeightReserved = 2 * ( + options.dividerHeightReserved + maxStackHeight + ) + print("Max Card Stack Height: {:.2f}cm ".format(maxStackHeight / 10.0)) # Adjust for rotation if options.rotate == 90 or options.rotate == 270: # for page calculations, this just means switching horizontal and vertical for these rotations. - options.dividerWidth, options.dividerHeight = options.dividerHeight, options.dividerWidth - options.dividerWidthReserved, options.dividerHeightReserved = (options.dividerHeightReserved, - options.dividerWidthReserved) + options.dividerWidth, options.dividerHeight = ( + options.dividerHeight, + options.dividerWidth, + ) + options.dividerWidthReserved, options.dividerHeightReserved = ( + options.dividerHeightReserved, + options.dividerWidthReserved, + ) options.dividerWidthReserved += options.horizontalBorderSpace options.dividerHeightReserved += options.verticalBorderSpace @@ -1511,40 +1746,78 @@ class DividerDrawer(object): # as we don't draw anything in the final border, it shouldn't count towards how many tabs we can fit # so it gets added back in to the page size here numDividersVerticalP = int( - (options.paperheight - 2 * options.minmarginheight + options.verticalBorderSpace) / - options.dividerHeightReserved) + ( + options.paperheight + - 2 * options.minmarginheight + + options.verticalBorderSpace + ) + / options.dividerHeightReserved + ) numDividersHorizontalP = int( - (options.paperwidth - 2 * options.minmarginwidth + options.horizontalBorderSpace) / - options.dividerWidthReserved) + ( + options.paperwidth + - 2 * options.minmarginwidth + + options.horizontalBorderSpace + ) + / options.dividerWidthReserved + ) numDividersVerticalL = int( - (options.paperwidth - 2 * options.minmarginwidth + options.verticalBorderSpace) / - options.dividerHeightReserved) + ( + options.paperwidth + - 2 * options.minmarginwidth + + options.verticalBorderSpace + ) + / options.dividerHeightReserved + ) numDividersHorizontalL = int( - (options.paperheight - 2 * options.minmarginheight + options.horizontalBorderSpace) / - options.dividerWidthReserved) + ( + options.paperheight + - 2 * options.minmarginheight + + options.horizontalBorderSpace + ) + / options.dividerWidthReserved + ) - if ((numDividersVerticalL * numDividersHorizontalL > numDividersVerticalP * - numDividersHorizontalP) and not options.fixedMargins) and options.rotate == 0: + if ( + ( + numDividersVerticalL * numDividersHorizontalL + > numDividersVerticalP * numDividersHorizontalP + ) + and not options.fixedMargins + ) and options.rotate == 0: options.numDividersVertical = numDividersVerticalL options.numDividersHorizontal = numDividersHorizontalL options.minHorizontalMargin = options.minmarginheight options.minVerticalMargin = options.minmarginwidth - options.paperheight, options.paperwidth = options.paperwidth, options.paperheight + options.paperheight, options.paperwidth = ( + options.paperwidth, + options.paperheight, + ) else: options.numDividersVertical = numDividersVerticalP options.numDividersHorizontal = numDividersHorizontalP options.minHorizontalMargin = options.minmarginheight options.minVerticalMargin = options.minmarginwidth - assert options.numDividersVertical > 0, "Could not vertically fit the divider on the page" - assert options.numDividersHorizontal > 0, "Could not horizontally fit the divider on the page" + assert ( + options.numDividersVertical > 0 + ), "Could not vertically fit the divider on the page" + assert ( + options.numDividersHorizontal > 0 + ), "Could not horizontally fit the divider on the page" if not options.fixedMargins: # dynamically max margins - options.horizontalMargin = (options.paperwidth - options.numDividersHorizontal * - options.dividerWidthReserved + options.horizontalBorderSpace) / 2 - options.verticalMargin = (options.paperheight - options.numDividersVertical * - options.dividerHeightReserved + options.verticalBorderSpace) / 2 + options.horizontalMargin = ( + options.paperwidth + - options.numDividersHorizontal * options.dividerWidthReserved + + options.horizontalBorderSpace + ) / 2 + options.verticalMargin = ( + options.paperheight + - options.numDividersVertical * options.dividerHeightReserved + + options.verticalBorderSpace + ) / 2 else: options.horizontalMargin = options.minmarginwidth options.verticalMargin = options.minmarginheight @@ -1561,10 +1834,10 @@ class DividerDrawer(object): # Drawing line type if options.cropmarks: - if 'dot' in options.linetype.lower(): - lineType = 'dot' # Allow the DOTs if requested + if "dot" in options.linetype.lower(): + lineType = "dot" # Allow the DOTs if requested else: - lineType = 'no_line' + lineType = "no_line" else: lineType = options.linetype.lower() @@ -1588,21 +1861,25 @@ class DividerDrawer(object): cardWidth, cardHeight = cardHeight, cardWidth # Initialized CardPlot tabs - CardPlot.tabSetup(tabNumber=options.tab_number, - cardWidth=cardWidth, - cardHeight=cardHeight, - lineType=lineType, - tabWidth=options.labelWidth, - tabHeight=options.labelHeight, - start=tabSideStart, - serpentine=options.tab_serpentine, - wrapper=options.wrapper) + CardPlot.tabSetup( + tabNumber=options.tab_number, + cardWidth=cardWidth, + cardHeight=cardHeight, + lineType=lineType, + tabWidth=options.labelWidth, + tabHeight=options.labelHeight, + start=tabSideStart, + serpentine=options.tab_serpentine, + wrapper=options.wrapper, + ) # Now go through all the cards and create their plotter information record... items = [] nextTabIndex = CardPlot.tabRestart() lastCardSet = None - reset_expansion_tabs = options.expansion_dividers and options.expansion_reset_tabs + reset_expansion_tabs = ( + options.expansion_dividers and options.expansion_reset_tabs + ) for card in cards: # Check if tab needs to be reset to the start @@ -1610,9 +1887,11 @@ class DividerDrawer(object): if lastCardSet != card.cardset_tag: # In a new expansion, so reset the tabs to start over nextTabIndex = CardPlot.tabRestart() - if options.tab_number > Card.sets[card.cardset_tag]['count']: + if options.tab_number > Card.sets[card.cardset_tag]["count"]: # Limit to the number of tabs to the number of dividers in the expansion - CardPlot.tabSetup(tabNumber=Card.sets[card.cardset_tag]['count']) + CardPlot.tabSetup( + tabNumber=Card.sets[card.cardset_tag]["count"] + ) elif CardPlot.tabNumber != options.tab_number: # Make sure tabs are set back to the original CardPlot.tabSetup(tabNumber=options.tab_number) @@ -1624,19 +1903,26 @@ class DividerDrawer(object): else: thisTabIndex = nextTabIndex - item = CardPlot(card, - rotation=options.spin if options.spin != 0 else options.rotate, - tabIndex=thisTabIndex, - textTypeFront=options.text_front, - textTypeBack=options.text_back, - stackHeight=card.getStackHeight(options.thickness) - ) - if options.flip and (options.tab_number == 2) and (thisTabIndex != CardPlot.tabStart): + item = CardPlot( + card, + rotation=options.spin if options.spin != 0 else options.rotate, + tabIndex=thisTabIndex, + textTypeFront=options.text_front, + textTypeBack=options.text_back, + stackHeight=card.getStackHeight(options.thickness), + ) + if ( + options.flip + and (options.tab_number == 2) + and (thisTabIndex != CardPlot.tabStart) + ): item.flipFront2Back() # Instead of flipping the tab, flip the whole divider front to back # Before moving on, setup the tab for the next item if this tab slot was used if thisTabIndex == nextTabIndex: - nextTabIndex = item.nextTab(nextTabIndex) # already used, so move on to the next tab + nextTabIndex = item.nextTab( + nextTabIndex + ) # already used, so move on to the next tab items.append(item) return items @@ -1648,8 +1934,14 @@ class DividerDrawer(object): columns = options.numDividersHorizontal numPerPage = rows * columns # Calculate if there is always enough room for horizontal and vertical crop marks - RoomForCropH = options.horizontalBorderSpace > 2*(options.cropmarkLength + options.cropmarkSpacing) * cm - RoomForCropV = options.verticalBorderSpace > 2*(options.cropmarkLength + options.cropmarkSpacing) * cm + RoomForCropH = ( + options.horizontalBorderSpace + > 2 * (options.cropmarkLength + options.cropmarkSpacing) * cm + ) + RoomForCropV = ( + options.verticalBorderSpace + > 2 * (options.cropmarkLength + options.cropmarkSpacing) * cm + ) items = split(items, numPerPage) pages = [] @@ -1685,18 +1977,24 @@ class DividerDrawer(object): # Front page footer if not self.options.no_page_footer and ( - not self.options.tabs_only and - self.options.order != "global"): + not self.options.tabs_only and self.options.order != "global" + ): self.drawSetNames(page) # Front page for item in page: # print the dividor - self.drawDivider(item, isBack=False, horizontalMargin=hMargin, verticalMargin=vMargin) + self.drawDivider( + item, isBack=False, horizontalMargin=hMargin, verticalMargin=vMargin + ) self.canvas.showPage() if pageNum + 1 == self.options.num_pages: break - if self.options.tabs_only or self.options.text_back == "none" or self.options.wrapper: + if ( + self.options.tabs_only + or self.options.text_back == "none" + or self.options.wrapper + ): # Don't print the sheets with the back of the dividers continue @@ -1707,7 +2005,9 @@ class DividerDrawer(object): # Back page for item in page: # print the dividor - self.drawDivider(item, isBack=True, horizontalMargin=hMargin, verticalMargin=vMargin) + self.drawDivider( + item, isBack=True, horizontalMargin=hMargin, verticalMargin=vMargin + ) self.canvas.showPage() if pageNum + 1 == self.options.num_pages: break diff --git a/domdiv/images/action-shelter.png b/src/domdiv/images/action-shelter.png similarity index 100% rename from domdiv/images/action-shelter.png rename to src/domdiv/images/action-shelter.png diff --git a/domdiv/images/action-treasure.png b/src/domdiv/images/action-treasure.png similarity index 100% rename from domdiv/images/action-treasure.png rename to src/domdiv/images/action-treasure.png diff --git a/domdiv/images/action-victory.png b/src/domdiv/images/action-victory.png similarity index 100% rename from domdiv/images/action-victory.png rename to src/domdiv/images/action-victory.png diff --git a/domdiv/images/action.png b/src/domdiv/images/action.png similarity index 100% rename from domdiv/images/action.png rename to src/domdiv/images/action.png diff --git a/domdiv/images/adventures_set.png b/src/domdiv/images/adventures_set.png similarity index 100% rename from domdiv/images/adventures_set.png rename to src/domdiv/images/adventures_set.png diff --git a/domdiv/images/alchemy_set.png b/src/domdiv/images/alchemy_set.png similarity index 100% rename from domdiv/images/alchemy_set.png rename to src/domdiv/images/alchemy_set.png diff --git a/domdiv/images/animals.png b/src/domdiv/images/animals.png similarity index 100% rename from domdiv/images/animals.png rename to src/domdiv/images/animals.png diff --git a/domdiv/images/artifact.png b/src/domdiv/images/artifact.png similarity index 100% rename from domdiv/images/artifact.png rename to src/domdiv/images/artifact.png diff --git a/domdiv/images/black_market_set.png b/src/domdiv/images/black_market_set.png similarity index 100% rename from domdiv/images/black_market_set.png rename to src/domdiv/images/black_market_set.png diff --git a/domdiv/images/boon.png b/src/domdiv/images/boon.png similarity index 100% rename from domdiv/images/boon.png rename to src/domdiv/images/boon.png diff --git a/domdiv/images/card.png b/src/domdiv/images/card.png similarity index 100% rename from domdiv/images/card.png rename to src/domdiv/images/card.png diff --git a/domdiv/images/coin.png b/src/domdiv/images/coin.png similarity index 100% rename from domdiv/images/coin.png rename to src/domdiv/images/coin.png diff --git a/domdiv/images/coin_small.png b/src/domdiv/images/coin_small.png similarity index 100% rename from domdiv/images/coin_small.png rename to src/domdiv/images/coin_small.png diff --git a/domdiv/images/coin_small_0.png b/src/domdiv/images/coin_small_0.png similarity index 100% rename from domdiv/images/coin_small_0.png rename to src/domdiv/images/coin_small_0.png diff --git a/domdiv/images/coin_small_1.png b/src/domdiv/images/coin_small_1.png similarity index 100% rename from domdiv/images/coin_small_1.png rename to src/domdiv/images/coin_small_1.png diff --git a/domdiv/images/coin_small_10.png b/src/domdiv/images/coin_small_10.png similarity index 100% rename from domdiv/images/coin_small_10.png rename to src/domdiv/images/coin_small_10.png diff --git a/domdiv/images/coin_small_11.png b/src/domdiv/images/coin_small_11.png similarity index 100% rename from domdiv/images/coin_small_11.png rename to src/domdiv/images/coin_small_11.png diff --git a/domdiv/images/coin_small_12.png b/src/domdiv/images/coin_small_12.png similarity index 100% rename from domdiv/images/coin_small_12.png rename to src/domdiv/images/coin_small_12.png diff --git a/domdiv/images/coin_small_13.png b/src/domdiv/images/coin_small_13.png similarity index 100% rename from domdiv/images/coin_small_13.png rename to src/domdiv/images/coin_small_13.png diff --git a/domdiv/images/coin_small_2.png b/src/domdiv/images/coin_small_2.png similarity index 100% rename from domdiv/images/coin_small_2.png rename to src/domdiv/images/coin_small_2.png diff --git a/domdiv/images/coin_small_3.png b/src/domdiv/images/coin_small_3.png similarity index 100% rename from domdiv/images/coin_small_3.png rename to src/domdiv/images/coin_small_3.png diff --git a/domdiv/images/coin_small_4.png b/src/domdiv/images/coin_small_4.png similarity index 100% rename from domdiv/images/coin_small_4.png rename to src/domdiv/images/coin_small_4.png diff --git a/domdiv/images/coin_small_5.png b/src/domdiv/images/coin_small_5.png similarity index 100% rename from domdiv/images/coin_small_5.png rename to src/domdiv/images/coin_small_5.png diff --git a/domdiv/images/coin_small_6.png b/src/domdiv/images/coin_small_6.png similarity index 100% rename from domdiv/images/coin_small_6.png rename to src/domdiv/images/coin_small_6.png diff --git a/domdiv/images/coin_small_7.png b/src/domdiv/images/coin_small_7.png similarity index 100% rename from domdiv/images/coin_small_7.png rename to src/domdiv/images/coin_small_7.png diff --git a/domdiv/images/coin_small_8.png b/src/domdiv/images/coin_small_8.png similarity index 100% rename from domdiv/images/coin_small_8.png rename to src/domdiv/images/coin_small_8.png diff --git a/domdiv/images/coin_small_9.png b/src/domdiv/images/coin_small_9.png similarity index 100% rename from domdiv/images/coin_small_9.png rename to src/domdiv/images/coin_small_9.png diff --git a/domdiv/images/coin_small_empty.png b/src/domdiv/images/coin_small_empty.png similarity index 100% rename from domdiv/images/coin_small_empty.png rename to src/domdiv/images/coin_small_empty.png diff --git a/domdiv/images/coin_small_question.png b/src/domdiv/images/coin_small_question.png similarity index 100% rename from domdiv/images/coin_small_question.png rename to src/domdiv/images/coin_small_question.png diff --git a/domdiv/images/cornucopia_set.png b/src/domdiv/images/cornucopia_set.png similarity index 100% rename from domdiv/images/cornucopia_set.png rename to src/domdiv/images/cornucopia_set.png diff --git a/domdiv/images/curse.png b/src/domdiv/images/curse.png similarity index 100% rename from domdiv/images/curse.png rename to src/domdiv/images/curse.png diff --git a/domdiv/images/dark_ages_set.png b/src/domdiv/images/dark_ages_set.png similarity index 100% rename from domdiv/images/dark_ages_set.png rename to src/domdiv/images/dark_ages_set.png diff --git a/domdiv/images/debt.png b/src/domdiv/images/debt.png similarity index 100% rename from domdiv/images/debt.png rename to src/domdiv/images/debt.png diff --git a/domdiv/images/debt_1.png b/src/domdiv/images/debt_1.png similarity index 100% rename from domdiv/images/debt_1.png rename to src/domdiv/images/debt_1.png diff --git a/domdiv/images/debt_2.png b/src/domdiv/images/debt_2.png similarity index 100% rename from domdiv/images/debt_2.png rename to src/domdiv/images/debt_2.png diff --git a/domdiv/images/debt_40.png b/src/domdiv/images/debt_40.png similarity index 100% rename from domdiv/images/debt_40.png rename to src/domdiv/images/debt_40.png diff --git a/domdiv/images/debt_5.png b/src/domdiv/images/debt_5.png similarity index 100% rename from domdiv/images/debt_5.png rename to src/domdiv/images/debt_5.png diff --git a/domdiv/images/debt_6.png b/src/domdiv/images/debt_6.png similarity index 100% rename from domdiv/images/debt_6.png rename to src/domdiv/images/debt_6.png diff --git a/domdiv/images/debt_8.png b/src/domdiv/images/debt_8.png similarity index 100% rename from domdiv/images/debt_8.png rename to src/domdiv/images/debt_8.png diff --git a/domdiv/images/dominion1stEdition_set.png b/src/domdiv/images/dominion1stEdition_set.png similarity index 100% rename from domdiv/images/dominion1stEdition_set.png rename to src/domdiv/images/dominion1stEdition_set.png diff --git a/domdiv/images/dominion2ndEdition_set.png b/src/domdiv/images/dominion2ndEdition_set.png similarity index 100% rename from domdiv/images/dominion2ndEdition_set.png rename to src/domdiv/images/dominion2ndEdition_set.png diff --git a/domdiv/images/duration-reaction.png b/src/domdiv/images/duration-reaction.png similarity index 100% rename from domdiv/images/duration-reaction.png rename to src/domdiv/images/duration-reaction.png diff --git a/domdiv/images/duration.png b/src/domdiv/images/duration.png similarity index 100% rename from domdiv/images/duration.png rename to src/domdiv/images/duration.png diff --git a/domdiv/images/empires_set.png b/src/domdiv/images/empires_set.png similarity index 100% rename from domdiv/images/empires_set.png rename to src/domdiv/images/empires_set.png diff --git a/domdiv/images/envoy_set.png b/src/domdiv/images/envoy_set.png similarity index 100% rename from domdiv/images/envoy_set.png rename to src/domdiv/images/envoy_set.png diff --git a/domdiv/images/event.png b/src/domdiv/images/event.png similarity index 100% rename from domdiv/images/event.png rename to src/domdiv/images/event.png diff --git a/domdiv/images/expansion.png b/src/domdiv/images/expansion.png similarity index 100% rename from domdiv/images/expansion.png rename to src/domdiv/images/expansion.png diff --git a/domdiv/images/governor_set.png b/src/domdiv/images/governor_set.png similarity index 100% rename from domdiv/images/governor_set.png rename to src/domdiv/images/governor_set.png diff --git a/domdiv/images/guilds_set.png b/src/domdiv/images/guilds_set.png similarity index 100% rename from domdiv/images/guilds_set.png rename to src/domdiv/images/guilds_set.png diff --git a/domdiv/images/hex.png b/src/domdiv/images/hex.png similarity index 100% rename from domdiv/images/hex.png rename to src/domdiv/images/hex.png diff --git a/domdiv/images/hinterlands_set.png b/src/domdiv/images/hinterlands_set.png similarity index 100% rename from domdiv/images/hinterlands_set.png rename to src/domdiv/images/hinterlands_set.png diff --git a/domdiv/images/intrigue1stEdition_set.png b/src/domdiv/images/intrigue1stEdition_set.png similarity index 100% rename from domdiv/images/intrigue1stEdition_set.png rename to src/domdiv/images/intrigue1stEdition_set.png diff --git a/domdiv/images/intrigue2ndEdition_set.png b/src/domdiv/images/intrigue2ndEdition_set.png similarity index 100% rename from domdiv/images/intrigue2ndEdition_set.png rename to src/domdiv/images/intrigue2ndEdition_set.png diff --git a/domdiv/images/landmark.png b/src/domdiv/images/landmark.png similarity index 100% rename from domdiv/images/landmark.png rename to src/domdiv/images/landmark.png diff --git a/domdiv/images/night.png b/src/domdiv/images/night.png similarity index 100% rename from domdiv/images/night.png rename to src/domdiv/images/night.png diff --git a/domdiv/images/nocturne_set.png b/src/domdiv/images/nocturne_set.png similarity index 100% rename from domdiv/images/nocturne_set.png rename to src/domdiv/images/nocturne_set.png diff --git a/domdiv/images/potion.png b/src/domdiv/images/potion.png similarity index 100% rename from domdiv/images/potion.png rename to src/domdiv/images/potion.png diff --git a/domdiv/images/potion_small.png b/src/domdiv/images/potion_small.png similarity index 100% rename from domdiv/images/potion_small.png rename to src/domdiv/images/potion_small.png diff --git a/domdiv/images/prince_set.png b/src/domdiv/images/prince_set.png similarity index 100% rename from domdiv/images/prince_set.png rename to src/domdiv/images/prince_set.png diff --git a/domdiv/images/project.png b/src/domdiv/images/project.png similarity index 100% rename from domdiv/images/project.png rename to src/domdiv/images/project.png diff --git a/domdiv/images/promo_set.png b/src/domdiv/images/promo_set.png similarity index 100% rename from domdiv/images/promo_set.png rename to src/domdiv/images/promo_set.png diff --git a/domdiv/images/prosperity_set.png b/src/domdiv/images/prosperity_set.png similarity index 100% rename from domdiv/images/prosperity_set.png rename to src/domdiv/images/prosperity_set.png diff --git a/domdiv/images/reaction-shelter.png b/src/domdiv/images/reaction-shelter.png similarity index 100% rename from domdiv/images/reaction-shelter.png rename to src/domdiv/images/reaction-shelter.png diff --git a/domdiv/images/reaction.png b/src/domdiv/images/reaction.png similarity index 100% rename from domdiv/images/reaction.png rename to src/domdiv/images/reaction.png diff --git a/domdiv/images/renaissance_set.png b/src/domdiv/images/renaissance_set.png similarity index 100% rename from domdiv/images/renaissance_set.png rename to src/domdiv/images/renaissance_set.png diff --git a/domdiv/images/reserve-treasure.png b/src/domdiv/images/reserve-treasure.png similarity index 100% rename from domdiv/images/reserve-treasure.png rename to src/domdiv/images/reserve-treasure.png diff --git a/domdiv/images/reserve-victory.png b/src/domdiv/images/reserve-victory.png similarity index 100% rename from domdiv/images/reserve-victory.png rename to src/domdiv/images/reserve-victory.png diff --git a/domdiv/images/reserve.png b/src/domdiv/images/reserve.png similarity index 100% rename from domdiv/images/reserve.png rename to src/domdiv/images/reserve.png diff --git a/domdiv/images/ruins.png b/src/domdiv/images/ruins.png similarity index 100% rename from domdiv/images/ruins.png rename to src/domdiv/images/ruins.png diff --git a/domdiv/images/seaside_set.png b/src/domdiv/images/seaside_set.png similarity index 100% rename from domdiv/images/seaside_set.png rename to src/domdiv/images/seaside_set.png diff --git a/domdiv/images/shelter.png b/src/domdiv/images/shelter.png similarity index 100% rename from domdiv/images/shelter.png rename to src/domdiv/images/shelter.png diff --git a/domdiv/images/stash_set.png b/src/domdiv/images/stash_set.png similarity index 100% rename from domdiv/images/stash_set.png rename to src/domdiv/images/stash_set.png diff --git a/domdiv/images/state.png b/src/domdiv/images/state.png similarity index 100% rename from domdiv/images/state.png rename to src/domdiv/images/state.png diff --git a/domdiv/images/treasure-reaction.png b/src/domdiv/images/treasure-reaction.png similarity index 100% rename from domdiv/images/treasure-reaction.png rename to src/domdiv/images/treasure-reaction.png diff --git a/domdiv/images/treasure-victory.png b/src/domdiv/images/treasure-victory.png similarity index 100% rename from domdiv/images/treasure-victory.png rename to src/domdiv/images/treasure-victory.png diff --git a/domdiv/images/treasure.png b/src/domdiv/images/treasure.png similarity index 100% rename from domdiv/images/treasure.png rename to src/domdiv/images/treasure.png diff --git a/domdiv/images/victory-reaction.png b/src/domdiv/images/victory-reaction.png similarity index 100% rename from domdiv/images/victory-reaction.png rename to src/domdiv/images/victory-reaction.png diff --git a/domdiv/images/victory-shelter.png b/src/domdiv/images/victory-shelter.png similarity index 100% rename from domdiv/images/victory-shelter.png rename to src/domdiv/images/victory-shelter.png diff --git a/domdiv/images/victory.png b/src/domdiv/images/victory.png similarity index 100% rename from domdiv/images/victory.png rename to src/domdiv/images/victory.png diff --git a/domdiv/images/victory_emblem.png b/src/domdiv/images/victory_emblem.png similarity index 100% rename from domdiv/images/victory_emblem.png rename to src/domdiv/images/victory_emblem.png diff --git a/domdiv/images/walled_village_set.png b/src/domdiv/images/walled_village_set.png similarity index 100% rename from domdiv/images/walled_village_set.png rename to src/domdiv/images/walled_village_set.png diff --git a/domdiv/main.py b/src/domdiv/main.py similarity index 71% rename from domdiv/main.py rename to src/domdiv/main.py index 234ad73..fa156fb 100644 --- a/domdiv/main.py +++ b/src/domdiv/main.py @@ -20,8 +20,16 @@ from .draw import DividerDrawer LOCATION_CHOICES = ["tab", "body-top", "hide"] NAME_ALIGN_CHOICES = ["left", "right", "centre", "edge"] -TAB_SIDE_CHOICES = ["left", "right", "left-alternate", "right-alternate", - "left-flip", "right-flip", "centre", "full"] +TAB_SIDE_CHOICES = [ + "left", + "right", + "left-alternate", + "right-alternate", + "left-flip", + "right-flip", + "centre", + "full", +] TEXT_CHOICES = ["card", "rules", "blank"] LINE_CHOICES = ["line", "dot", "cropmarks", "dot-cropmarks"] @@ -29,21 +37,25 @@ EDITION_CHOICES = ["1", "2", "latest", "all"] ORDER_CHOICES = ["expansion", "global", "colour", "cost"] -LANGUAGE_DEFAULT = 'en_us' # the primary language used if a language's parts are missing -LANGUAGE_XX = 'xx' # a dummy language for starting translations +LANGUAGE_DEFAULT = ( + "en_us" +) # the primary language used if a language's parts are missing +LANGUAGE_XX = "xx" # a dummy language for starting translations def get_languages(path): languages = [] - for name in pkg_resources.resource_listdir('domdiv', path): + for name in pkg_resources.resource_listdir("domdiv", path): dir_path = os.path.join(path, name) - if pkg_resources.resource_isdir('domdiv', dir_path): + if pkg_resources.resource_isdir("domdiv", dir_path): cards_file = os.path.join(dir_path, "cards_{}.json".format(name)) sets_file = os.path.join(dir_path, "sets_{}.json".format(name)) types_file = os.path.join(dir_path, "types_{}.json".format(name)) - if (pkg_resources.resource_exists('domdiv', cards_file) and - pkg_resources.resource_exists('domdiv', sets_file) and - pkg_resources.resource_exists('domdiv', types_file)): + if ( + pkg_resources.resource_exists("domdiv", cards_file) + and pkg_resources.resource_exists("domdiv", sets_file) + and pkg_resources.resource_exists("domdiv", types_file) + ): languages.append(name) if LANGUAGE_XX in languages: languages.remove(LANGUAGE_XX) @@ -54,22 +66,22 @@ LANGUAGE_CHOICES = get_languages("card_db") def get_resource_stream(path): - return codecs.EncodedFile(pkg_resources.resource_stream('domdiv', path), "utf-8") + return codecs.EncodedFile(pkg_resources.resource_stream("domdiv", path), "utf-8") def get_expansions(): set_db_filepath = os.path.join("card_db", "sets_db.json") with get_resource_stream(set_db_filepath) as setfile: - set_file = json.loads(setfile.read().decode('utf-8')) + set_file = json.loads(setfile.read().decode("utf-8")) assert set_file, "Could not load any sets from database" fan = [] official = [] for s in set_file: - if 'extras' not in s: + if "extras" not in s: # Make sure this are set either True or False - set_file[s]['fan'] = set_file[s].get('fan', False) - if set_file[s]['fan']: + set_file[s]["fan"] = set_file[s].get("fan", False) + if set_file[s]["fan"]: fan.append(s) else: official.append(s) @@ -81,12 +93,14 @@ def get_expansions(): EXPANSION_CHOICES, FAN_CHOICES = get_expansions() -def get_types(language='en_us'): +def get_types(language="en_us"): # get a list of valid types language = language.lower() - type_text_filepath = os.path.join("card_db", language, "types_{}.json".format(language)) + type_text_filepath = os.path.join( + "card_db", language, "types_{}.json".format(language) + ) with get_resource_stream(type_text_filepath) as type_text_file: - type_text = json.loads(type_text_file.read().decode('utf-8')) + type_text = json.loads(type_text_file.read().decode("utf-8")) assert type_text, "Could not load type file for %r" % language types = [x.lower() for x in type_text] @@ -104,13 +118,13 @@ LABEL_KEYS = [] LABEL_SELECTIONS = [] labels_db_filepath = os.path.join("card_db", "labels_db.json") with get_resource_stream(labels_db_filepath) as labelfile: - LABEL_INFO = json.loads(labelfile.read().decode('utf-8')) + LABEL_INFO = json.loads(labelfile.read().decode("utf-8")) assert LABEL_INFO, "Could not load label information from database" for label in LABEL_INFO: - if len(label['names']) > 0: - LABEL_KEYS.append(label['names'][0]) - LABEL_SELECTIONS.append(label['name'] if 'name' in label else label['names'][0]) - LABEL_CHOICES.extend(label['names']) + if len(label["names"]) > 0: + LABEL_KEYS.append(label["names"][0]) + LABEL_SELECTIONS.append(label["name"] if "name" in label else label["names"][0]) + LABEL_CHOICES.extend(label["names"]) def add_opt(options, option, value): @@ -123,47 +137,53 @@ def parse_opts(cmdline_args=None): formatter_class=argparse.ArgumentDefaultsHelpFormatter, description="Generate Dominion Dividers", epilog="Source can be found at 'https://github.com/sumpfork/dominiontabs'. " - "An online version can be found at 'http://domtabs.sandflea.org/'. ") + "An online version can be found at 'http://domtabs.sandflea.org/'. ", + ) # Basic Divider Information group_basic = parser.add_argument_group( - 'Basic Divider Options', - 'Basic choices for the dividers.') + "Basic Divider Options", "Basic choices for the dividers." + ) group_basic.add_argument( - '--outfile', '-o', + "--outfile", + "-o", dest="outfile", default="dominion_dividers.pdf", - help="The output file name.") + help="The output file name.", + ) group_basic.add_argument( "--papersize", dest="papersize", default=None, help="The size of paper to use; '<%%f>x<%%f>' (size in cm), or 'A4', or 'LETTER'. " "If not specified, it will default to system defaults, and if the system defaults " - "are not found, then to 'LETTER'.") + "are not found, then to 'LETTER'.", + ) group_basic.add_argument( - "--language", "-l", + "--language", + "-l", dest="language", default=LANGUAGE_DEFAULT, choices=LANGUAGE_CHOICES, - help="Language of divider text.") + help="Language of divider text.", + ) group_basic.add_argument( "--orientation", choices=["horizontal", "vertical"], dest="orientation", default="horizontal", - help="Either horizontal or vertical divider orientation.") + help="Either horizontal or vertical divider orientation.", + ) group_basic.add_argument( "--size", dest="size", - default='normal', + default="normal", help="Dimentions of the cards to use with the dividers '<%%f>x<%%f>' (size in cm), " - "or 'normal' = '9.1x5.9', or 'sleeved' = '9.4x6.15'.") + "or 'normal' = '9.1x5.9', or 'sleeved' = '9.4x6.15'.", + ) group_basic.add_argument( - "--sleeved", - action="store_true", - dest="sleeved", - help="Same as --size=sleeved.") + "--sleeved", action="store_true", dest="sleeved", help="Same as --size=sleeved." + ) group_basic.add_argument( "--order", choices=ORDER_CHOICES, @@ -173,12 +193,13 @@ def parse_opts(cmdline_args=None): " 'global' will sort by card name;" " 'expansion' will sort by expansion, then card name;" " 'colour' will sort by card type, then card name;" - " 'cost' will sort by expansion, then card cost, then name.") + " 'cost' will sort by expansion, then card cost, then name.", + ) # Divider Body group_body = parser.add_argument_group( - 'Divider Body', - 'Changes what is displayed on the body of the dividers.') + "Divider Body", "Changes what is displayed on the body of the dividers." + ) group_body.add_argument( "--front", choices=TEXT_CHOICES, @@ -187,7 +208,8 @@ def parse_opts(cmdline_args=None): help="Text to print on the front of the divider; " "'card' will print the text from the game card; " "'rules' will print additional rules for the game card; " - "'blank' will not print text on the divider.") + "'blank' will not print text on the divider.", + ) group_body.add_argument( "--back", choices=TEXT_CHOICES + ["none"], @@ -197,23 +219,26 @@ def parse_opts(cmdline_args=None): "'card' will print the text from the game card; " "'rules' will print additional rules for the game card; " "'blank' will not print text on the divider; " - "'none' will prevent the back pages from printing. ") + "'none' will prevent the back pages from printing. ", + ) group_body.add_argument( "--count", action="store_true", dest="count", help="Display the card count on the body of card dividers " - "and the randomizer count on the body of expansion dividers.") + "and the randomizer count on the body of expansion dividers.", + ) group_body.add_argument( "--types", action="store_true", dest="types", - help="Display card type on the body of the divider.") + help="Display card type on the body of the divider.", + ) # Divider Tab group_tab = parser.add_argument_group( - 'Divider Tab', - 'Changes what is displayed on on the Divider Tab.') + "Divider Tab", "Changes what is displayed on on the Divider Tab." + ) group_tab.add_argument( "--tab-side", choices=TAB_SIDE_CHOICES, @@ -229,24 +254,27 @@ def parse_opts(cmdline_args=None): "'left-flip' like left-alternate, but the right will be flipped front/back with tab on left," " sets --tab_number 2; " "'right-flip' like right-alternate, but the left will be flipped front/back with tab on right," - " sets --tab_number 2; ") + " sets --tab_number 2; ", + ) group_tab.add_argument( "--tab-number", type=int, default=1, help="The number of tabs. When set to 1, all tabs are on the same side (specified by --tab_side). " - "When set to 2, tabs will alternate between left and right. (starting side specified by --tab_side). " - "When set > 2, the first tab will be on left/right side specified by --tab_side, then the rest " - "of the tabs will be evenly spaced until ending on the opposite side. Then the cycle repeats. " - "May be overriden by some options of --tab_side.") + "When set to 2, tabs will alternate between left and right. (starting side specified by --tab_side). " + "When set > 2, the first tab will be on left/right side specified by --tab_side, then the rest " + "of the tabs will be evenly spaced until ending on the opposite side. Then the cycle repeats. " + "May be overriden by some options of --tab_side.", + ) group_tab.add_argument( "--tab-serpentine", action="store_true", help="Affects the order of tabs. When not selected, tabs will progress from the starting side (left/right) " - "to the opposite side (right/left), and then repeat (e.g., left to right, left to right, etc.). " - "When selected, the order is changed to smoothly alternate between the two sides " - "(e.g., left to right, to left, to right, etc.) " - "Only valid if --tab_number > 2.") + "to the opposite side (right/left), and then repeat (e.g., left to right, left to right, etc.). " + "When selected, the order is changed to smoothly alternate between the two sides " + "(e.g., left to right, to left, to right, etc.) " + "Only valid if --tab_number > 2.", + ) group_tab.add_argument( "--tab-name-align", choices=NAME_ALIGN_CHOICES + ["center"], @@ -256,73 +284,84 @@ def parse_opts(cmdline_args=None): "The 'edge' option will align the card name to the outside edge of the " "tab, so that when using tabs on alternating sides, " "the name is less likely to be hidden by the tab in front " - "(edge will revert to left when tab_side is full since there is no edge in that case).") + "(edge will revert to left when tab_side is full since there is no edge in that case).", + ) group_tab.add_argument( "--tabwidth", type=float, default=4.0, - help="Width in cm of stick-up tab (ignored if --tab_side is 'full' or --tabs_only is used).") + help="Width in cm of stick-up tab (ignored if --tab_side is 'full' or --tabs_only is used).", + ) group_tab.add_argument( "--cost", action="append", choices=LOCATION_CHOICES, - default=['tab'], + default=["tab"], help="Where to display the card cost; may be set to " "'hide' to indicate it should not be displayed, or " - "given multiple times to show it in multiple places.") + "given multiple times to show it in multiple places.", + ) group_tab.add_argument( "--set-icon", action="append", choices=LOCATION_CHOICES, - default=['tab'], + default=["tab"], help="Where to display the set icon; may be set to " "'hide' to indicate it should not be displayed, or " - "given multiple times to show it in multiple places.") + "given multiple times to show it in multiple places.", + ) group_tab.add_argument( "--no-tab-artwork", action="store_true", dest="no_tab_artwork", - help="Don't show background artwork on tabs.") + help="Don't show background artwork on tabs.", + ) group_tab.add_argument( "--use-text-set-icon", action="store_true", dest="use_text_set_icon", - help="Use text/letters to represent a card's set instead of the set icon.") + help="Use text/letters to represent a card's set instead of the set icon.", + ) # Expanion Dividers group_expansion = parser.add_argument_group( - 'Expansion Dividers', - 'Adding separator dividers for each expansion.') + "Expansion Dividers", "Adding separator dividers for each expansion." + ) group_expansion.add_argument( "--expansion-dividers", action="store_true", dest="expansion_dividers", help="Add dividers describing each expansion set. " - "A list of cards in the expansion will be shown on the front of the divider.") + "A list of cards in the expansion will be shown on the front of the divider.", + ) group_expansion.add_argument( "--centre-expansion-dividers", action="store_true", dest="centre_expansion_dividers", - help='Centre the tabs on expansion dividers.') + help="Centre the tabs on expansion dividers.", + ) group_expansion.add_argument( "--expansion-reset-tabs", action="store_true", dest="expansion_reset_tabs", help="When set, the tabs are restarted (left/right) at the beginning of each expansion. " - "If not set, the tab pattern will continue from one expansion to the next. ") + "If not set, the tab pattern will continue from one expansion to the next. ", + ) group_expansion.add_argument( "--expansion-dividers-long-name", action="store_true", dest="expansion_dividers_long_name", help="Use the long name with edition information on the expansion divider tab. " - "Without this, the shorter expansion name is used on the expansion divider tab.") + "Without this, the shorter expansion name is used on the expansion divider tab.", + ) # Divider Selection group_select = parser.add_argument_group( - 'Divider Selection', - 'What expansions are used, and grouping of dividers.') + "Divider Selection", "What expansions are used, and grouping of dividers." + ) group_select.add_argument( - "--expansions", "--expansion", + "--expansions", + "--expansion", nargs="*", action="append", dest="expansions", @@ -335,7 +374,10 @@ def parse_opts(cmdline_args=None): "'*' any number of characters, '?' matches any single character, " "'[seq]' matches any character in seq, and '[!seq]' matches any character not in seq. " "For example, 'dominion*' will match all expansions that start with 'dominion'. " - "Choices available in all languages include: {}".format(", ".join("%s" % x for x in EXPANSION_CHOICES))) + "Choices available in all languages include: {}".format( + ", ".join("%s" % x for x in EXPANSION_CHOICES) + ), + ) group_select.add_argument( "--fan", nargs="*", @@ -349,7 +391,10 @@ def parse_opts(cmdline_args=None): "Values are not case sensitive. Wildcards may be used: " "'*' any number of characters, '?' matches any single character, " "'[seq]' matches any character in seq, and '[!seq]' matches any character not in seq. " - "Choices available in all languages include: {}".format(", ".join("%s" % x for x in FAN_CHOICES))) + "Choices available in all languages include: {}".format( + ", ".join("%s" % x for x in FAN_CHOICES) + ), + ) group_select.add_argument( "--edition", choices=EDITION_CHOICES, @@ -360,53 +405,65 @@ def parse_opts(cmdline_args=None): "'2' is for all 2nd Editions; " "'latest' is for the latest edition for each expansion; " "'all' is for all editions of expansions; " - " This can be combined with other options to refine the expansions to include in the output.") + " This can be combined with other options to refine the expansions to include in the output.", + ) group_select.add_argument( "--upgrade-with-expansion", action="store_true", dest="upgrade_with_expansion", - help="Include any new edition upgrade cards with the expansion being upgraded.") + help="Include any new edition upgrade cards with the expansion being upgraded.", + ) group_select.add_argument( "--base-cards-with-expansion", action="store_true", help="Print the base cards as part of the expansion (i.e., a divider for 'Silver' " "will be printed as both a 'Dominion' card and as an 'Intrigue 1st Edition' card). " - "If this option is not given, all base cards are placed in their own 'Base' expansion.") + "If this option is not given, all base cards are placed in their own 'Base' expansion.", + ) group_select.add_argument( "--special-card-groups", action="store_true", help="Group cards that generally are used together " - "(e.g., Shelters, Tournament and Prizes, Urchin/Mercenary, etc.).") + "(e.g., Shelters, Tournament and Prizes, Urchin/Mercenary, etc.).", + ) group_select.add_argument( "--no-trash", action="store_true", dest="no_trash", - help="Exclude Trash from cards.") + help="Exclude Trash from cards.", + ) group_select.add_argument( "--curse10", action="store_true", dest="curse10", - help="Package Curse cards into groups of ten cards.") + help="Package Curse cards into groups of ten cards.", + ) group_select.add_argument( "--start-decks", action="store_true", dest="start_decks", - help="Include four start decks with the Base cards.") + help="Include four start decks with the Base cards.", + ) group_select.add_argument( "--include-blanks", type=int, default=0, - help="Number of blank dividers to include.") + help="Number of blank dividers to include.", + ) group_select.add_argument( "--exclude-events", action="store_true", - help="Group all 'Event' cards across all expansions into one divider.") + help="Group all 'Event' cards across all expansions into one divider.", + ) group_select.add_argument( "--exclude-landmarks", action="store_true", - help="Group all 'Landmark' cards across all expansions into one divider.") + help="Group all 'Landmark' cards across all expansions into one divider.", + ) group_select.add_argument( - "--only-type-any", "--only-type", "--type-any", + "--only-type-any", + "--only-type", + "--type-any", nargs="*", action="append", dest="only_type_any", @@ -415,9 +472,13 @@ def parse_opts(cmdline_args=None): "Default is all types are included. " "Any type with a space in the name must be enclosed in double quotes. " "Values are not case sensitive. " - "Choices available in all languages include: {}".format(", ".join("%s" % x for x in TYPE_CHOICES))) + "Choices available in all languages include: {}".format( + ", ".join("%s" % x for x in TYPE_CHOICES) + ), + ) group_select.add_argument( - "--only-type-all", "--type-all", + "--only-type-all", + "--type-all", nargs="*", action="append", dest="only_type_all", @@ -425,34 +486,41 @@ def parse_opts(cmdline_args=None): "A divider is kept if ALL of the provided types are associated with the divider. " "Any type with a space in the name must be enclosed in double quotes. " "Values are not case sensitive. " - "Choices available in all languages include: {}".format(", ".join("%s" % x for x in TYPE_CHOICES))) + "Choices available in all languages include: {}".format( + ", ".join("%s" % x for x in TYPE_CHOICES) + ), + ) # Divider Sleeves/Wrappers group_wrapper = parser.add_argument_group( - 'Card Sleeves/Wrappers', - 'Generating dividers that are card sleeves/wrappers.') + "Card Sleeves/Wrappers", "Generating dividers that are card sleeves/wrappers." + ) group_wrapper.add_argument( "--wrapper", action="store_true", dest="wrapper", - help="Draw sleeves (aka wrapper) for the cards instead of a divider for the cards.") + help="Draw sleeves (aka wrapper) for the cards instead of a divider for the cards.", + ) group_wrapper.add_argument( "--thickness", type=float, default=2.0, help="Thickness of a stack of 60 cards (Copper) in centimeters. " "Typically unsleeved cards are 2.0, thin sleeved cards are 2.4, and thick sleeved cards are 3.2. " - "This is only valid with the --wrapper option.") + "This is only valid with the --wrapper option.", + ) group_wrapper.add_argument( "--sleeved-thick", action="store_true", dest="sleeved_thick", - help="Same as --size=sleeved --thickness 3.2.") + help="Same as --size=sleeved --thickness 3.2.", + ) group_wrapper.add_argument( "--sleeved-thin", action="store_true", dest="sleeved_thin", - help="Same as --size=sleeved --thickness 2.4.") + help="Same as --size=sleeved --thickness 2.4.", + ) group_wrapper.add_argument( "--notch-length", type=float, @@ -460,74 +528,86 @@ def parse_opts(cmdline_args=None): help="Length of thumb notch on wrapper in centimeters " "(a value of 0.0 means no notch on wrapper). " "This can make it easier to remove the actual cards from the wrapper. " - "This is only valid with the --wrapper option.") + "This is only valid with the --wrapper option.", + ) group_wrapper.add_argument( "--notch", action="store_true", dest="notch", - help="Same as --notch_length thickness 1.5.") + help="Same as --notch_length thickness 1.5.", + ) # Printing group_printing = parser.add_argument_group( - 'Printing', - 'Changes how the Dividers are printed.') + "Printing", "Changes how the Dividers are printed." + ) group_printing.add_argument( "--minmargin", dest="minmargin", default="1x1", - help="Page margin in cm in the form '<%%f>x<%%f>', left/right x top/bottom).") + help="Page margin in cm in the form '<%%f>x<%%f>', left/right x top/bottom).", + ) group_printing.add_argument( "--cropmarks", action="store_true", dest="cropmarks", - help="Print crop marks on both sides, rather than tab outlines on the front side.") + help="Print crop marks on both sides, rather than tab outlines on the front side.", + ) group_printing.add_argument( "--linewidth", type=float, default=0.1, - help="Width of lines for card outlines and crop marks.") + help="Width of lines for card outlines and crop marks.", + ) group_printing.add_argument( "--back-offset", type=float, dest="back_offset", default=0, - help="Back page horizontal offset points to shift to the right. Only needed for some printers.") + help="Back page horizontal offset points to shift to the right. Only needed for some printers.", + ) group_printing.add_argument( "--back-offset-height", type=float, dest="back_offset_height", default=0, - help="Back page vertical offset points to shift upward. Only needed for some printers.") + help="Back page vertical offset points to shift upward. Only needed for some printers.", + ) group_printing.add_argument( "--vertical-gap", type=float, default=0.0, - help="Vertical gap between dividers in centimeters.") + help="Vertical gap between dividers in centimeters.", + ) group_printing.add_argument( "--horizontal-gap", type=float, default=0.0, - help="Horizontal gap between dividers in centimeters.") + help="Horizontal gap between dividers in centimeters.", + ) group_printing.add_argument( "--no-page-footer", action="store_true", dest="no_page_footer", - help="Do not print the expansion name at the bottom of the page.") + help="Do not print the expansion name at the bottom of the page.", + ) group_printing.add_argument( "--num-pages", type=int, default=-1, - help="Stop generating dividers after this many pages, -1 for all.") + help="Stop generating dividers after this many pages, -1 for all.", + ) group_printing.add_argument( "--tabs-only", action="store_true", dest="tabs_only", help="Draw only the divider tabs and no divider outlines. " - "Used to print the divider tabs on labels.") + "Used to print the divider tabs on labels.", + ) group_printing.add_argument( "--black-tabs", action="store_true", - help="In tabs-only mode, draw tabs on black background" + help="In tabs-only mode, draw tabs on black background", ) group_printing.add_argument( "--linetype", @@ -538,64 +618,74 @@ def parse_opts(cmdline_args=None): "'line' will print a solid line outlining the divider; " "'dot' will print a dot at each corner of the divider; " "'cropmarks' will print cropmarks for the divider; " - "'dot-cropmarks' will combine 'dot' and 'cropmarks'") + "'dot-cropmarks' will combine 'dot' and 'cropmarks'", + ) group_printing.add_argument( "--cropmarkLength", type=float, default=0.2, - help="Length of actual drawn cropmark in centimeters.") + help="Length of actual drawn cropmark in centimeters.", + ) group_printing.add_argument( "--cropmarkSpacing", type=float, default=0.1, - help="Spacing between card and the start of the cropmark in centimeters.") + help="Spacing between card and the start of the cropmark in centimeters.", + ) group_printing.add_argument( "--rotate", type=int, choices=[0, 90, 180, 270], default=0, help="Divider degrees of rotation relative to the page edge. " - "No optimization will be done on the number of dividers per page.") + "No optimization will be done on the number of dividers per page.", + ) group_printing.add_argument( "--label", dest="label_name", choices=LABEL_CHOICES, default=None, help="Use preset label dimentions. Specify a label name. " - "This will override settings that conflict with the preset label settings.") + "This will override settings that conflict with the preset label settings.", + ) group_printing.add_argument( "--info", action="store_true", dest="info", - help="Add a page that has all the options used for the file.") + help="Add a page that has all the options used for the file.", + ) group_printing.add_argument( "--info-all", action="store_true", dest="info_all", - help="Same as --info, but includes pages with all the possible options that can be used.") + help="Same as --info, but includes pages with all the possible options that can be used.", + ) group_printing.add_argument( "--preview", - action='store_true', - help="Only generate a preview png image of the first page" + action="store_true", + help="Only generate a preview png image of the first page", ) group_printing.add_argument( "--preview-resolution", type=int, default=150, - help="resolution in DPI to render preview at, for --preview option") + help="resolution in DPI to render preview at, for --preview option", + ) # Special processing group_special = parser.add_argument_group( - 'Miscellaneous', - 'These options are generally not used.') + "Miscellaneous", "These options are generally not used." + ) group_special.add_argument( "--cardlist", dest="cardlist", - help="Path to file that enumerates each card to be printed on its own line.") + help="Path to file that enumerates each card to be printed on its own line.", + ) group_special.add_argument( "--write-json", action="store_true", dest="write_json", - help="Write json version of card definitions and extras.") + help="Write json version of card definitions and extras.", + ) options = parser.parse_args(args=cmdline_args) # Need to do these while we have access to the parser @@ -626,14 +716,20 @@ def clean_opts(options): if "-alternate" in options.tab_side: if options.tab_number != 2: - print("** Warning: --tab-side with 'alternate' implies 2 tabs. Setting --tab-number to 2 **") + print( + "** Warning: --tab-side with 'alternate' implies 2 tabs. Setting --tab-number to 2 **" + ) options.tab_number = 2 # alternating left and right, so override tab_number if "-flip" in options.tab_side: # for left and right tabs if options.tab_number != 2: - print("** Warning: --tab-side with 'flip' implies 2 tabs. Setting --tab-number to 2 **") - options.tab_number = 2 # alternating left and right with a flip, so override tab_number + print( + "** Warning: --tab-side with 'flip' implies 2 tabs. Setting --tab-number to 2 **" + ) + options.tab_number = ( + 2 + ) # alternating left and right with a flip, so override tab_number options.flip = True else: options.flip = False @@ -656,23 +752,25 @@ def clean_opts(options): if options.notch_length > 0: options.notch_height = 0.25 # thumb notch height - if options.cropmarks and options.linetype == 'line': - options.linetype = 'cropmarks' + if options.cropmarks and options.linetype == "line": + options.linetype = "cropmarks" - if options.linetype == 'cropmarks': + if options.linetype == "cropmarks": options.cropmarks = True - if options.linetype == 'dot-cropmarks': - options.linetype = 'dot' + if options.linetype == "dot-cropmarks": + options.linetype = "dot" options.cropmarks = True if options.expansions is None: # No instance given, so default to all Official expansions - options.expansions = ['*'] + options.expansions = ["*"] else: # options.expansions is a list of lists. Reduce to single lowercase list - options.expansions = [item.lower() for sublist in options.expansions for item in sublist] - if 'none' in options.expansions: + options.expansions = [ + item.lower() for sublist in options.expansions for item in sublist + ] + if "none" in options.expansions: # keyword to indicate no options. Same as --expansions without any expansions given. options.expansions = [] @@ -682,7 +780,7 @@ def clean_opts(options): else: # options.fan is a list of lists. Reduce to single lowercase list options.fan = [item.lower() for sublist in options.fan for item in sublist] - if 'none' in options.fan: + if "none" in options.fan: # keyword to indicate no options. Same as --fan without any expansions given options.fan = [] @@ -691,14 +789,18 @@ def clean_opts(options): options.only_type_any = [] else: # options.only_type_any is a list of lists. Reduce to single lowercase list - options.only_type_any = list(set([item.lower() for sublist in options.only_type_any for item in sublist])) + options.only_type_any = list( + set([item.lower() for sublist in options.only_type_any for item in sublist]) + ) if options.only_type_all is None: # No instance given, so default to empty list options.only_type_all = [] else: # options.only_type_any is a list of lists. Reduce to single lowercase list - options.only_type_all = list(set([item.lower() for sublist in options.only_type_all for item in sublist])) + options.only_type_all = list( + set([item.lower() for sublist in options.only_type_all for item in sublist]) + ) if options.tabs_only and options.label_name is None: # default is Avery 8867 @@ -707,22 +809,38 @@ def clean_opts(options): options.label = None if options.label_name is not None: for label in LABEL_INFO: - if options.label_name.upper() in [n.upper() for n in label['names']]: + if options.label_name.upper() in [n.upper() for n in label["names"]]: options.label = label break - assert options.label is not None, "Label '{}' not defined".format(options.label_name) + assert options.label is not None, "Label '{}' not defined".format( + options.label_name + ) # Defaults for missing values label = options.label - label['paper'] = label['paper'] if 'paper' in label else "LETTER" - label['tab-only'] = label['tab-only'] if 'tab-only' in label else True - label['tab-height'] = label['tab-height'] if 'tab-height' in label else label['height'] - label['body-height'] = label['body-height'] if 'body-height' in label else label['height'] - label['tab-height'] - label['gap-vertical'] = label['gap-vertical'] if 'gap-vertical' in label else 0.0 - label['gap-horizontal'] = label['gap-horizontal'] if 'gap-horizontal' in label else 0.0 - label['pad-vertical'] = label['pad-vertical'] if 'pad-vertical' in label else 0.1 - label['pad-horizontal'] = label['pad-horizontal'] if 'pad-horizontal' in label else 0.1 + label["paper"] = label["paper"] if "paper" in label else "LETTER" + label["tab-only"] = label["tab-only"] if "tab-only" in label else True + label["tab-height"] = ( + label["tab-height"] if "tab-height" in label else label["height"] + ) + label["body-height"] = ( + label["body-height"] + if "body-height" in label + else label["height"] - label["tab-height"] + ) + label["gap-vertical"] = ( + label["gap-vertical"] if "gap-vertical" in label else 0.0 + ) + label["gap-horizontal"] = ( + label["gap-horizontal"] if "gap-horizontal" in label else 0.0 + ) + label["pad-vertical"] = ( + label["pad-vertical"] if "pad-vertical" in label else 0.1 + ) + label["pad-horizontal"] = ( + label["pad-horizontal"] if "pad-horizontal" in label else 0.1 + ) # Option Overrides when using labels MIN_BODY_CM_FOR_COUNT = 0.6 @@ -733,21 +851,23 @@ def clean_opts(options): options.linewidth = 0.0 options.cropmarks = False options.wrapper = False - options.papersize = label['paper'] - if label['tab-only']: + options.papersize = label["paper"] + if label["tab-only"]: options.tabs_only = True - if label['body-height'] < MIN_BODY_CM_FOR_TEXT: + if label["body-height"] < MIN_BODY_CM_FOR_TEXT: # Not enough room for any text options.text_front = "blank" options.text_back = "blank" - if label['body-height'] < MIN_BODY_CM_FOR_COUNT: + if label["body-height"] < MIN_BODY_CM_FOR_COUNT: # Not enough room for count and type options.count = False options.types = False - if label['height'] < MIN_HEIGHT_CM_FOR_VERTICAL: + if label["height"] < MIN_HEIGHT_CM_FOR_VERTICAL: # Not enough room to make vertical options.orientation = "horizontal" - if (options.label['width'] - 2 * options.label['pad-horizontal']) < MIN_WIDTH_CM_FOR_FULL: + if ( + options.label["width"] - 2 * options.label["pad-horizontal"] + ) < MIN_WIDTH_CM_FOR_FULL: options.tab_side = "full" options.label = label @@ -755,20 +875,21 @@ def clean_opts(options): def parseDimensions(dimensionsStr): - x, y = dimensionsStr.upper().split('X', 1) + x, y = dimensionsStr.upper().split("X", 1) return (float(x) * cm, float(y) * cm) def generate_sample(options): from io import BytesIO from wand.image import Image + buf = BytesIO() options.num_pages = 1 options.outfile = buf generate(options) sample_out = BytesIO() with Image(blob=buf.getvalue(), resolution=options.preview_resolution) as sample: - sample.format = 'png' + sample.format = "png" sample.save(sample_out) return sample_out.getvalue() @@ -779,7 +900,7 @@ def parse_papersize(spec): if os.path.exists("/etc/papersize"): papersize = open("/etc/papersize").readline().upper() else: - papersize = 'LETTER' + papersize = "LETTER" else: papersize = spec.upper() @@ -788,8 +909,13 @@ def parse_papersize(spec): except AttributeError: try: paperwidth, paperheight = parseDimensions(papersize) - print(('Using custom paper size, {:.2f}cm x {:.2f}cm'.format( - paperwidth / cm, paperheight / cm))) + print( + ( + "Using custom paper size, {:.2f}cm x {:.2f}cm".format( + paperwidth / cm, paperheight / cm + ) + ) + ) except ValueError: paperwidth, paperheight = pagesizes.LETTER return paperwidth, paperheight @@ -797,18 +923,33 @@ def parse_papersize(spec): def parse_cardsize(spec, sleeved): spec = spec.upper() - if spec == 'SLEEVED' or sleeved: + if spec == "SLEEVED" or sleeved: dominionCardWidth, dominionCardHeight = (9.4 * cm, 6.15 * cm) - print(('Using sleeved card size, {:.2f}cm x {:.2f}cm'.format( - dominionCardWidth / cm, dominionCardHeight / cm))) - elif spec in ['NORMAL', 'UNSLEEVED']: + print( + ( + "Using sleeved card size, {:.2f}cm x {:.2f}cm".format( + dominionCardWidth / cm, dominionCardHeight / cm + ) + ) + ) + elif spec in ["NORMAL", "UNSLEEVED"]: dominionCardWidth, dominionCardHeight = (9.1 * cm, 5.9 * cm) - print(('Using normal card size, {:.2f}cm x{:.2f}cm'.format( - dominionCardWidth / cm, dominionCardHeight / cm))) + print( + ( + "Using normal card size, {:.2f}cm x{:.2f}cm".format( + dominionCardWidth / cm, dominionCardHeight / cm + ) + ) + ) else: dominionCardWidth, dominionCardHeight = parseDimensions(spec) - print(('Using custom card size, {:.2f}cm x {:.2f}cm'.format( - dominionCardWidth / cm, dominionCardHeight / cm))) + print( + ( + "Using custom card size, {:.2f}cm x {:.2f}cm".format( + dominionCardWidth / cm, dominionCardHeight / cm + ) + ) + ) return dominionCardWidth, dominionCardHeight @@ -843,7 +984,9 @@ def read_card_data(options): # Read in the card types types_db_filepath = os.path.join("card_db", "types_db.json") with get_resource_stream(types_db_filepath) as typefile: - Card.types = json.loads(typefile.read().decode('utf-8'), object_hook=CardType.decode_json) + Card.types = json.loads( + typefile.read().decode("utf-8"), object_hook=CardType.decode_json + ) assert Card.types, "Could not load any card types from database" # extract unique types @@ -861,27 +1004,29 @@ def read_card_data(options): # Read in the card database card_db_filepath = os.path.join("card_db", "cards_db.json") with get_resource_stream(card_db_filepath) as cardfile: - cards = json.loads(cardfile.read().decode('utf-8'), object_hook=Card.decode_json) + cards = json.loads( + cardfile.read().decode("utf-8"), object_hook=Card.decode_json + ) assert cards, "Could not load any cards from database" set_db_filepath = os.path.join("card_db", "sets_db.json") with get_resource_stream(set_db_filepath) as setfile: - Card.sets = json.loads(setfile.read().decode('utf-8')) + Card.sets = json.loads(setfile.read().decode("utf-8")) assert Card.sets, "Could not load any sets from database" for s in Card.sets: # Make sure these are set either True or False - Card.sets[s]['no_randomizer'] = Card.sets[s].get('no_randomizer', False) - Card.sets[s]['fan'] = Card.sets[s].get('fan', False) + Card.sets[s]["no_randomizer"] = Card.sets[s].get("no_randomizer", False) + Card.sets[s]["fan"] = Card.sets[s].get("fan", False) # Remove the Trash card. Do early before propagating to various sets. if options.no_trash: - i = find_index_of_object(cards, {'card_tag': 'Trash'}) + i = find_index_of_object(cards, {"card_tag": "Trash"}) if i is not None: del cards[i] # Repackage Curse cards into 10 per divider. Do early before propagating to various sets. if options.curse10: - i = find_index_of_object(cards, {'card_tag': 'Curse'}) + i = find_index_of_object(cards, {"card_tag": "Curse"}) if i is not None: new_cards = [] cards_remaining = cards[i].getCardCount() @@ -900,12 +1045,14 @@ def read_card_data(options): # Add any blank cards if options.include_blanks > 0: for x in range(0, options.include_blanks): - c = Card(card_tag=u'Blank', - cardset='extras', - cardset_tag='extras', - cardset_tags=['extras'], - randomizer=False, - types=("Blank", )) + c = Card( + card_tag=u"Blank", + cardset="extras", + cardset_tag="extras", + cardset_tags=["extras"], + randomizer=False, + types=("Blank",), + ) cards.append(c) # Create Start Deck dividers. 4 sets. Adjust totals for other cards, too. @@ -913,9 +1060,9 @@ def read_card_data(options): # The card database contains one prototype divider that needs to be either duplicated or deleted. if options.start_decks: # Find the index to the individual cards that need changed in the cards list - StartDeck_index = find_index_of_object(cards, {'card_tag': 'Start Deck'}) - Copper_index = find_index_of_object(cards, {'card_tag': 'Copper'}) - Estate_index = find_index_of_object(cards, {'card_tag': 'Estate'}) + StartDeck_index = find_index_of_object(cards, {"card_tag": "Start Deck"}) + Copper_index = find_index_of_object(cards, {"card_tag": "Copper"}) + Estate_index = find_index_of_object(cards, {"card_tag": "Estate"}) if Copper_index is None or Estate_index is None or StartDeck_index is None: # Something is wrong, can't find one or more of the cards that need to change print("Error - cannot create Start Decks") @@ -942,11 +1089,15 @@ def read_card_data(options): # Note: By appending, it should not change any of the index values being used # Remove Copper and Estate card counts from their dividers - cards[Copper_index].setCardCount(cards[Copper_index].getCardCount() - STARTDECK_COPPERS) - cards[Estate_index].setCardCount(cards[Estate_index].getCardCount() - STARTDECK_ESTATES) + cards[Copper_index].setCardCount( + cards[Copper_index].getCardCount() - STARTDECK_COPPERS + ) + cards[Estate_index].setCardCount( + cards[Estate_index].getCardCount() - STARTDECK_ESTATES + ) else: # Remove Start Deck prototype. It is not needed. - StartDeck_index = find_index_of_object(cards, {'card_tag': 'Start Deck'}) + StartDeck_index = find_index_of_object(cards, {"card_tag": "Start Deck"}) if StartDeck_index is not None: del cards[StartDeck_index] @@ -985,9 +1136,20 @@ class CardSorter(object): else: self.sort_key = self.by_expansion_sort_key - self.baseOrder = ['Copper', 'Silver', 'Gold', 'Platinum', 'Potion', - 'Curse', 'Estate', 'Duchy', 'Province', 'Colony', - 'Trash', 'Start Deck'] + self.baseOrder = [ + "Copper", + "Silver", + "Gold", + "Platinum", + "Potion", + "Curse", + "Estate", + "Duchy", + "Province", + "Colony", + "Trash", + "Start Deck", + ] self.baseCards = [] for tag in self.baseOrder: if tag in baseCards: @@ -1008,60 +1170,76 @@ class CardSorter(object): return -1 def isBaseExpansionCard(self, card): - return card.cardset_tag.lower() != 'base' and card.name in self.baseCards + return card.cardset_tag.lower() != "base" and card.name in self.baseCards def by_global_sort_key(self, card): - return int(card.isExpansion()), self.baseIndex(card.name), self.strip_accents(card.name) + return ( + int(card.isExpansion()), + self.baseIndex(card.name), + self.strip_accents(card.name), + ) def by_expansion_sort_key(self, card): - return card.cardset, int(card.isExpansion()), self.baseIndex( - card.name), self.strip_accents(card.name) + return ( + card.cardset, + int(card.isExpansion()), + self.baseIndex(card.name), + self.strip_accents(card.name), + ) def by_colour_sort_key(self, card): return card.getType().getTypeNames(), self.strip_accents(card.name) def by_cost_sort_key(self, card): - return card.cardset, int(card.isExpansion()), card.get_total_cost(card), self.strip_accents(card.name) + return ( + card.cardset, + int(card.isExpansion()), + card.get_total_cost(card), + self.strip_accents(card.name), + ) @staticmethod def strip_accents(s): - return ''.join(c for c in unicodedata.normalize('NFD', s) - if unicodedata.category(c) != 'Mn') + return "".join( + c + for c in unicodedata.normalize("NFD", s) + if unicodedata.category(c) != "Mn" + ) def __call__(self, card): return self.sort_key(card) -def add_card_text(cards, language='en_us'): +def add_card_text(cards, language="en_us"): language = language.lower() # Read in the card text file - card_text_filepath = os.path.join("card_db", - language, - "cards_" + language.lower() + ".json") + card_text_filepath = os.path.join( + "card_db", language, "cards_" + language.lower() + ".json" + ) with get_resource_stream(card_text_filepath) as card_text_file: - card_text = json.loads(card_text_file.read().decode('utf-8')) + card_text = json.loads(card_text_file.read().decode("utf-8")) assert language, "Could not load card text for %r" % language # Now apply to all the cards for card in cards: if card.card_tag in card_text: - if 'name' in card_text[card.card_tag].keys(): - card.name = card_text[card.card_tag]['name'] - if 'description' in card_text[card.card_tag].keys(): - card.description = card_text[card.card_tag]['description'] - if 'extra' in card_text[card.card_tag].keys(): - card.extra = card_text[card.card_tag]['extra'] + if "name" in card_text[card.card_tag].keys(): + card.name = card_text[card.card_tag]["name"] + if "description" in card_text[card.card_tag].keys(): + card.description = card_text[card.card_tag]["description"] + if "extra" in card_text[card.card_tag].keys(): + card.extra = card_text[card.card_tag]["extra"] return cards -def add_set_text(options, sets, language='en_us'): +def add_set_text(options, sets, language="en_us"): language = language.lower() # Read in the set text and store for later - set_text_filepath = os.path.join("card_db", - language, - "sets_{}.json".format(language)) + set_text_filepath = os.path.join( + "card_db", language, "sets_{}.json".format(language) + ) with get_resource_stream(set_text_filepath) as set_text_file: - set_text = json.loads(set_text_file.read().decode('utf-8')) + set_text = json.loads(set_text_file.read().decode("utf-8")) assert set_text, "Could not load set text for %r" % language # Now apply to all the sets @@ -1072,14 +1250,14 @@ def add_set_text(options, sets, language='en_us'): return sets -def add_type_text(types={}, language='en_us'): +def add_type_text(types={}, language="en_us"): language = language.lower() # Read in the type text and store for later - type_text_filepath = os.path.join("card_db", - language, - "types_{}.json".format(language)) + type_text_filepath = os.path.join( + "card_db", language, "types_{}.json".format(language) + ) with get_resource_stream(type_text_filepath) as type_text_file: - type_text = json.loads(type_text_file.read().decode('utf-8')) + type_text = json.loads(type_text_file.read().decode("utf-8")) assert type_text, "Could not load type text for %r" % language # Now apply to all the types @@ -1096,14 +1274,14 @@ def add_type_text(types={}, language='en_us'): return types -def add_bonus_regex(options, language='en_us'): +def add_bonus_regex(options, language="en_us"): language = language.lower() # Read in the bonus regex terms - bonus_regex_filepath = os.path.join("card_db", - language, - "bonuses_{}.json".format(language)) + bonus_regex_filepath = os.path.join( + "card_db", language, "bonuses_{}.json".format(language) + ) with get_resource_stream(bonus_regex_filepath) as bonus_regex_file: - bonus_regex = json.loads(bonus_regex_file.read().decode('utf-8')) + bonus_regex = json.loads(bonus_regex_file.read().decode("utf-8")) assert bonus_regex, "Could not load bonus keywords for %r" % language if not bonus_regex: @@ -1114,12 +1292,14 @@ def add_bonus_regex(options, language='en_us'): def combine_cards(cards, old_card_type, new_card_tag, new_cardset_tag, new_type): - holder = Card(name='*Replace Later*', - card_tag=new_card_tag, - group_tag=new_card_tag, - cardset_tag=new_cardset_tag, - types=(new_type, ), - count=0) + holder = Card( + name="*Replace Later*", + card_tag=new_card_tag, + group_tag=new_card_tag, + cardset_tag=new_cardset_tag, + types=(new_type,), + count=0, + ) holder.image = holder.setImage() filteredCards = [] @@ -1155,32 +1335,34 @@ def filter_sort_cards(cards, options): # Combine upgrade cards with their expansion if options.upgrade_with_expansion: for card in cards: - if card.cardset_tag == 'dominion2ndEditionUpgrade': - card.cardset_tag = 'dominion1stEdition' + if card.cardset_tag == "dominion2ndEditionUpgrade": + card.cardset_tag = "dominion1stEdition" options.expansions.append(card.cardset_tag.lower()) - elif card.cardset_tag == 'intrigue2ndEditionUpgrade': - card.cardset_tag = 'intrigue1stEdition' + elif card.cardset_tag == "intrigue2ndEditionUpgrade": + card.cardset_tag = "intrigue1stEdition" options.expansions.append(card.cardset_tag.lower()) # Combine all Events across all expansions if options.exclude_events: - cards = combine_cards(cards, - old_card_type="Event", - new_type="Events", - new_card_tag='events', - new_cardset_tag='extras' - ) + cards = combine_cards( + cards, + old_card_type="Event", + new_type="Events", + new_card_tag="events", + new_cardset_tag="extras", + ) if options.expansions: options.expansions.append("extras") # Combine all Landmarks across all expansions if options.exclude_landmarks: - cards = combine_cards(cards, - old_card_type="Landmark", - new_type="Landmarks", - new_card_tag='landmarks', - new_cardset_tag='extras' - ) + cards = combine_cards( + cards, + old_card_type="Landmark", + new_type="Landmarks", + new_card_tag="landmarks", + new_cardset_tag="extras", + ) if options.expansions: options.expansions.append("extras") @@ -1195,7 +1377,7 @@ def filter_sort_cards(cards, options): # Group all the special cards together if options.special_card_groups: - keep_cards = [] # holds the cards that are to be kept + keep_cards = [] # holds the cards that are to be kept group_cards = {} # holds the cards for each group for card in cards: if not card.group_tag: @@ -1208,13 +1390,18 @@ def filter_sort_cards(cards, options): # this card becomes the card holder for the whole group. card.card_tag = card.group_tag # These text fields should be updated later if there is a translation for this group_tag. - error_msg = "ERROR: Missing language entry for group_tab '%s'." % card.group_tag - card.name = card.group_tag # For now, change the name to the group_tab + error_msg = ( + "ERROR: Missing language entry for group_tab '%s'." + % card.group_tag + ) + card.name = ( + card.group_tag + ) # For now, change the name to the group_tab card.description = error_msg card.extra = error_msg - if card.isType('Event') or card.isType('Project'): + if card.isType("Event") or card.isType("Project"): card.cost = "*" - if card.isType('Landmark'): + if card.isType("Landmark"): card.cost = "" # now save the card keep_cards.append(card) @@ -1229,7 +1416,9 @@ def filter_sort_cards(cards, options): group_cards[card.group_tag].randomizer = card.randomizer group_cards[card.group_tag].image = card.image - group_cards[card.group_tag].addCardCount(card.count) # increase the count + group_cards[card.group_tag].addCardCount( + card.count + ) # increase the count # group_cards[card.group_tag].set_lowest_cost(card) # set holder to lowest cost of the two cards cards = keep_cards @@ -1237,11 +1426,13 @@ def filter_sort_cards(cards, options): # Now fix up card costs for card in cards: if card.card_tag in group_cards: - if group_cards[card.group_tag].isType('Event') or group_cards[card.group_tag].isType('Project'): + if group_cards[card.group_tag].isType("Event") or group_cards[ + card.group_tag + ].isType("Project"): group_cards[card.group_tag].cost = "*" group_cards[card.group_tag].debtcost = 0 group_cards[card.group_tag].potcost = 0 - if group_cards[card.group_tag].isType('Landmark'): + if group_cards[card.group_tag].isType("Landmark"): group_cards[card.group_tag].cost = "" group_cards[card.group_tag].debtcost = 0 group_cards[card.group_tag].potcost = 0 @@ -1251,7 +1442,7 @@ def filter_sort_cards(cards, options): if options.language != LANGUAGE_DEFAULT: Card.type_names = add_type_text(Card.type_names, options.language) for card in cards: - card.types_name = ' - '.join([Card.type_names[t] for t in card.types]).upper() + card.types_name = " - ".join([Card.type_names[t] for t in card.types]).upper() # Get the card bonus keywords in the requested language bonus = add_bonus_regex(options, LANGUAGE_DEFAULT) @@ -1267,7 +1458,9 @@ def filter_sort_cards(cards, options): # Split out Official and Fan set information Official_sets = set() # Will hold official sets - Official_search = [] # Will hold official sets for searching, both set key and set_name + Official_search = ( + [] + ) # Will hold official sets for searching, both set key and set_name Fan_sets = set() # Will hold fan sets Fan_search = [] # Will hold fan sets for searching, both set key and set_name wantedSets = set() # Will hold all the sets requested for printing @@ -1275,11 +1468,13 @@ def filter_sort_cards(cards, options): if Card.sets[s].get("fan", False): # Fan Expansion Fan_sets.add(s) - Fan_search.extend([s.lower(), Card.sets[s].get('set_name', None).lower()]) + Fan_search.extend([s.lower(), Card.sets[s].get("set_name", None).lower()]) else: # Official Expansion Official_sets.add(s) - Official_search.extend([s.lower(), Card.sets[s].get('set_name', None).lower()]) + Official_search.extend( + [s.lower(), Card.sets[s].get("set_name", None).lower()] + ) # If expansion names given, then find out which expansions are requested # Expansion names can be the names from the language or the cardset_tag @@ -1298,13 +1493,19 @@ def filter_sort_cards(cards, options): knownExpansions = set() for e in options.expansions: for s in Official_sets: - if (s.lower() == e or Card.sets[s].get('set_name', "").lower() == e): + if s.lower() == e or Card.sets[s].get("set_name", "").lower() == e: wantedSets.add(s) knownExpansions.add(e) # Give indication if an imput did not match anything unknownExpansions = options.expansions - knownExpansions if unknownExpansions: - print(("Error - unknown expansion(s): {}".format(", ".join(unknownExpansions)))) + print( + ( + "Error - unknown expansion(s): {}".format( + ", ".join(unknownExpansions) + ) + ) + ) # Take care of fan expansions. Fan expansions must be explicitly named to be added. # If no --fan is given, then no fan cards are added. @@ -1324,7 +1525,7 @@ def filter_sort_cards(cards, options): knownExpansions = set() for e in options.fan: for s in Fan_sets: - if (s.lower() == e or Card.sets[s].get('set_name', "").lower() == e): + if s.lower() == e or Card.sets[s].get("set_name", "").lower() == e: wantedSets.add(s) knownExpansions.add(e) # Give indication if an imput did not match anything @@ -1337,7 +1538,7 @@ def filter_sort_cards(cards, options): for c in cards: if c.cardset_tag in wantedSets: # Add the cardset informaiton to the card and add it to the list of cards to use - c.cardset = Card.sets[c.cardset_tag].get('set_name', c.cardset_tag) + c.cardset = Card.sets[c.cardset_tag].get("set_name", c.cardset_tag) keep_cards.append(c) cards = keep_cards @@ -1358,12 +1559,16 @@ def filter_sort_cards(cards, options): # Set up the card sorter cardSorter = CardSorter( options.order, - {card.card_tag: card.name for card in cards if 'base' in [set_name.lower() for set_name in card.cardset_tags]}) + { + card.card_tag: card.name + for card in cards + if "base" in [set_name.lower() for set_name in card.cardset_tags] + }, + ) # Optionally remove base cards from expansions that have them if not options.base_cards_with_expansion: - cards = [card for card in cards - if not cardSorter.isBaseExpansionCard(card)] + cards = [card for card in cards if not cardSorter.isBaseExpansionCard(card)] # Add expansion divider if options.expansion_dividers: @@ -1378,17 +1583,19 @@ def filter_sort_cards(cards, options): if c.card_tag in cardnamesByExpansion[c.cardset]: # Already have one, so just update the count (for extra Curses, Start Decks, etc) - cardnamesByExpansion[c.cardset][c.card_tag]['count'] += 1 + cardnamesByExpansion[c.cardset][c.card_tag]["count"] += 1 else: # New, so save off information about the card to be used on the expansion divider order = 0 if c.card_tag in cardSorter.baseOrder: # Use the base card ordering order = 100 + cardSorter.baseOrder.index(c.card_tag) - cardnamesByExpansion[c.cardset][c.card_tag] = {'name': c.name.strip().replace(' ', ' '), - 'randomizer': c.randomizer, - 'count': 1, - 'sort': "%03d%s" % (order, c.name.strip(),)} + cardnamesByExpansion[c.cardset][c.card_tag] = { + "name": c.name.strip().replace(" ", " "), + "randomizer": c.randomizer, + "count": 1, + "sort": "%03d%s" % (order, c.name.strip()), + } for set_tag, set_values in Card.sets.items(): exp = set_values["set_name"] @@ -1396,34 +1603,40 @@ def filter_sort_cards(cards, options): exp_name = exp count = randomizerCountByExpansion[exp] - Card.sets[set_tag]['count'] = count - if 'no_randomizer' in set_values: - if set_values['no_randomizer']: + Card.sets[set_tag]["count"] = count + if "no_randomizer" in set_values: + if set_values["no_randomizer"]: count = 0 if not options.expansion_dividers_long_name: - if 'short_name' in set_values: - exp_name = set_values['short_name'] + if "short_name" in set_values: + exp_name = set_values["short_name"] card_names = [] - for n in sorted(cardnamesByExpansion[exp].values(), key=lambda x: x['sort']): - if not n['randomizer']: + for n in sorted( + cardnamesByExpansion[exp].values(), key=lambda x: x["sort"] + ): + if not n["randomizer"]: # Highlight cards without Randomizers - n['name'] = '' + n['name'] + '' - if n['count'] > 1: + n["name"] = "" + n["name"] + "" + if n["count"] > 1: # Add number of copies - n['name'] = u"{} \u00d7 ".format(n['count']) + n['name'] - card_names.append(n['name']) + n["name"] = ( + u"{} \u00d7 ".format(n["count"]) + n["name"] + ) + card_names.append(n["name"]) - c = Card(name=exp_name, - cardset=exp, - cardset_tag=set_tag, - types=("Expansion", ), - cost=None, - description=' | '.join(card_names), - extra=set_values.get("set_text", ""), - count=count, - card_tag=set_tag) + c = Card( + name=exp_name, + cardset=exp, + cardset_tag=set_tag, + types=("Expansion",), + cost=None, + description=" | ".join(card_names), + extra=set_values.get("set_text", ""), + count=count, + card_tag=set_tag, + ) cards.append(c) # Take care of any --only-type-xxx requirements @@ -1456,7 +1669,9 @@ def filter_sort_cards(cards, options): type_unknown.append(x) # Indicate if unknown types are given - assert not type_unknown, "Error - unknown type(s): {}".format(", ".join(type_unknown)) + assert not type_unknown, "Error - unknown type(s): {}".format( + ", ".join(type_unknown) + ) # If there are any valid Types left, go through the cards and keep cards that match if type_known_any or type_known_all: @@ -1482,7 +1697,9 @@ def filter_sort_cards(cards, options): def calculate_layout(options, cards=[]): # This is in place to allow for test cases to it call directly to get options = clean_opts(options) - options.dominionCardWidth, options.dominionCardHeight = parse_cardsize(options.size, options.sleeved) + options.dominionCardWidth, options.dominionCardHeight = parse_cardsize( + options.size, options.sleeved + ) options.paperwidth, options.paperheight = parse_papersize(options.papersize) options.minmarginwidth, options.minmarginheight = parseDimensions(options.minmargin) @@ -1500,14 +1717,26 @@ def generate(options): dd = calculate_layout(options, cards) - print("Paper dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format( - options.paperwidth / cm, options.paperheight / cm)) - print("Tab dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format( - options.dividerWidthReserved / cm, options.dividerHeightReserved / cm)) - print('{} dividers horizontally, {} vertically'.format( - options.numDividersHorizontal, options.numDividersVertical)) - print("Margins: {:.2f}cm h, {:.2f}cm v\n".format( - options.horizontalMargin / cm, options.verticalMargin / cm)) + print( + "Paper dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format( + options.paperwidth / cm, options.paperheight / cm + ) + ) + print( + "Tab dimensions: {:.2f}cm (w) x {:.2f}cm (h)".format( + options.dividerWidthReserved / cm, options.dividerHeightReserved / cm + ) + ) + print( + "{} dividers horizontally, {} vertically".format( + options.numDividersHorizontal, options.numDividersVertical + ) + ) + print( + "Margins: {:.2f}cm h, {:.2f}cm v\n".format( + options.horizontalMargin / cm, options.verticalMargin / cm + ) + ) dd.draw(cards) @@ -1516,7 +1745,7 @@ def main(): options = parse_opts() options = clean_opts(options) if options.preview: - fname = '{}.{}'.format(os.path.splitext(options.outfile)[0], 'png') - open(fname, 'wb').write(generate_sample(options).getvalue()) + fname = "{}.{}".format(os.path.splitext(options.outfile)[0], "png") + open(fname, "wb").write(generate_sample(options).getvalue()) else: generate(options) diff --git a/domdiv/tests/__init__.py b/tests/__init__.py similarity index 100% rename from domdiv/tests/__init__.py rename to tests/__init__.py diff --git a/domdiv/tests/carddb_tests.py b/tests/carddb_tests.py similarity index 55% rename from domdiv/tests/carddb_tests.py rename to tests/carddb_tests.py index 8dfd92e..a1b457c 100644 --- a/domdiv/tests/carddb_tests.py +++ b/tests/carddb_tests.py @@ -6,18 +6,18 @@ import contextlib import pytest -from .. import main -from .. import cards as domdiv_cards +from domdiv import main +from domdiv import cards as domdiv_cards @pytest.fixture def rmtestcardb(request): - def rmd(): - testcardb_dir = os.path.join(str(request.config.rootdir), 'tools/card_db') + testcardb_dir = os.path.join(str(request.config.rootdir), "tools/card_db") if os.path.exists(testcardb_dir): - print('removing {}'.format(testcardb_dir)) + print("removing {}".format(testcardb_dir)) shutil.rmtree(testcardb_dir) + request.addfinalizer(rmd) @@ -25,45 +25,47 @@ def test_cardread(): cardsExpected = 574 options = main.parse_opts([]) - options.data_path = '.' + options.data_path = "." cards = main.read_card_data(options) assert len(cards) == cardsExpected valid_cardsets = { - u'base', - u'dominion1stEdition', - u'dominion2ndEdition', - u'dominion2ndEditionUpgrade', - u'intrigue1stEdition', - u'intrigue2ndEdition', - u'intrigue2ndEditionUpgrade', - u'seaside', - u'alchemy', - u'prosperity', - u'cornucopia extras', - u'cornucopia', - u'hinterlands', - u'dark ages', - u'dark ages extras', - u'guilds', - u'adventures', - u'adventures extras', - u'empires', - u'empires extras', - u'nocturne', - u'nocturne extras', - u'promo', - u'renaissance', - u'extras', - u'animals' + u"base", + u"dominion1stEdition", + u"dominion2ndEdition", + u"dominion2ndEditionUpgrade", + u"intrigue1stEdition", + u"intrigue2ndEdition", + u"intrigue2ndEditionUpgrade", + u"seaside", + u"alchemy", + u"prosperity", + u"cornucopia extras", + u"cornucopia", + u"hinterlands", + u"dark ages", + u"dark ages extras", + u"guilds", + u"adventures", + u"adventures extras", + u"empires", + u"empires extras", + u"nocturne", + u"nocturne extras", + u"promo", + u"renaissance", + u"extras", + u"animals", } for c in cards: assert isinstance(c, domdiv_cards.Card) assert c.cardset_tag in valid_cardsets # Option modified card count - options = main.parse_opts(['--no-trash', '--curse10', '--start-decks', '--include-blanks', '7']) + options = main.parse_opts( + ["--no-trash", "--curse10", "--start-decks", "--include-blanks", "7"] + ) options = main.clean_opts(options) - options.data_path = '.' + options.data_path = "." cards = main.read_card_data(options) # Total delta cards is +28 from # Trash: -1 * 3 sets = -3 @@ -74,19 +76,19 @@ def test_cardread(): def test_languages(): - languages = main.get_languages('card_db') + languages = main.get_languages("card_db") for lang in languages: - print('checking ' + lang) + print("checking " + lang) # for now, just test that they load - options = main.parse_opts(['--language', lang]) - options.data_path = '.' + options = main.parse_opts(["--language", lang]) + options.data_path = "." cards = main.read_card_data(options) assert cards, '"{}" cards did not read properly'.format(lang) - cards = main.add_card_text(cards, 'en_us') + cards = main.add_card_text(cards, "en_us") cards = main.add_card_text(cards, lang) - if lang == 'it': + if lang == "it": assert "Maledizione" in [card.name for card in cards] - elif lang == 'de': + elif lang == "de": assert "Fluch" in [card.name for card in cards] @@ -102,24 +104,35 @@ def change_cwd(d): def test_languagetool_run(pytestconfig): with change_cwd(str(pytestconfig.rootdir)): - cmd = 'python tools/update_language.py' + cmd = "python tools/update_language.py" print(cmd) assert subprocess.check_call(cmd.split()) == 0 - cmd = 'diff -rwB domdiv/card_db tools/card_db' + cmd = "diff -rwB src/domdiv/card_db tools/card_db" try: out = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) except subprocess.CalledProcessError as e: - assert e.output == '' - assert out.decode('utf-8') == '' + assert e.output == "" + assert out.decode("utf-8") == "" def test_only_type(): - options = main.parse_opts(['--expansions', 'base', 'alchemy', - '--include-blanks', '5', - '--only-type-any', 'blank', 'curse', - '--only-type-all', 'attack', 'action']) + options = main.parse_opts( + [ + "--expansions", + "base", + "alchemy", + "--include-blanks", + "5", + "--only-type-any", + "blank", + "curse", + "--only-type-all", + "attack", + "action", + ] + ) options = main.clean_opts(options) - options.data_path = '.' + options.data_path = "." cards = main.read_card_data(options) cards = main.filter_sort_cards(cards, options) # Total 8 from diff --git a/domdiv/tests/generation_tests.py b/tests/generation_tests.py similarity index 62% rename from domdiv/tests/generation_tests.py rename to tests/generation_tests.py index 3b965b9..6984f2b 100644 --- a/domdiv/tests/generation_tests.py +++ b/tests/generation_tests.py @@ -2,7 +2,7 @@ from __future__ import print_function import pytest -from .. import main +from domdiv import main def get_clean_opts(opts): @@ -17,8 +17,8 @@ def test_standard_opts(): main.generate(options) -@pytest.mark.parametrize("lang", main.get_languages('card_db')) +@pytest.mark.parametrize("lang", main.get_languages("card_db")) def test_grouped(lang): - print('checking ' + lang) - options = get_clean_opts(['--special-card-groups', '--language={}'.format(lang)]) + print("checking " + lang) + options = get_clean_opts(["--special-card-groups", "--language={}".format(lang)]) main.generate(options) diff --git a/domdiv/tests/layout_tests.py b/tests/layout_tests.py similarity index 79% rename from domdiv/tests/layout_tests.py rename to tests/layout_tests.py index 69ffd89..79d98b9 100644 --- a/domdiv/tests/layout_tests.py +++ b/tests/layout_tests.py @@ -1,12 +1,12 @@ from reportlab.lib.units import cm -from .. import main +from domdiv import main def test_horizontal(): # should be the default options = main.parse_opts([]) - assert options.orientation == 'horizontal' + assert options.orientation == "horizontal" main.calculate_layout(options) assert options.numDividersHorizontal == 2 assert options.numDividersVertical == 3 @@ -16,8 +16,8 @@ def test_horizontal(): def test_vertical(): - options = main.parse_opts(['--orientation', 'vertical']) - assert options.orientation == 'vertical' + options = main.parse_opts(["--orientation", "vertical"]) + assert options.orientation == "vertical" main.calculate_layout(options) assert options.numDividersHorizontal == 3 assert options.numDividersVertical == 2 @@ -27,7 +27,7 @@ def test_vertical(): def test_sleeved(): - options = main.parse_opts(['--size', 'sleeved']) + options = main.parse_opts(["--size", "sleeved"]) main.calculate_layout(options) assert options.dividerWidth == 9.4 * cm assert options.labelHeight == 0.9 * cm diff --git a/tests/text_tab_tests.py b/tests/text_tab_tests.py new file mode 100644 index 0000000..8843ac3 --- /dev/null +++ b/tests/text_tab_tests.py @@ -0,0 +1,315 @@ +from domdiv import main + + +#################### +# Card Text and Tab Default Test +#################### +def test_text_tabs_default(): + # should be the default + options = main.parse_opts([]) + assert options.text_front == "card" + assert options.text_back == "rules" + assert options.tab_name_align == "left" + assert options.tab_side == "right-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "left" + + +#################### +# Card Text Tests +#################### + + +def test_text_card_rules(): + options = main.parse_opts(["--front", "card", "--back", "rules"]) + assert options.text_front == "card" + assert options.text_back == "rules" + + +def test_text_card_blank(): + options = main.parse_opts(["--front", "card", "--back", "blank"]) + assert options.text_front == "card" + assert options.text_back == "blank" + + +def test_text_card_card(): + options = main.parse_opts(["--front", "card", "--back", "card"]) + assert options.text_front == "card" + assert options.text_back == "card" + + +def test_text_card_none(): + options = main.parse_opts(["--front", "card", "--back", "none"]) + assert options.text_front == "card" + assert options.text_back == "none" + + +def test_text_rules_rules(): + options = main.parse_opts(["--front", "rules", "--back", "rules"]) + assert options.text_front == "rules" + assert options.text_back == "rules" + + +def test_text_rules_blank(): + options = main.parse_opts(["--front", "rules", "--back", "blank"]) + assert options.text_front == "rules" + assert options.text_back == "blank" + + +def test_text_rules_card(): + options = main.parse_opts(["--front", "rules", "--back", "card"]) + assert options.text_front == "rules" + assert options.text_back == "card" + + +def test_text_rules_none(): + options = main.parse_opts(["--front", "rules", "--back", "none"]) + assert options.text_front == "rules" + assert options.text_back == "none" + + +def test_text_blank_rules(): + options = main.parse_opts(["--front", "blank", "--back", "rules"]) + assert options.text_front == "blank" + assert options.text_back == "rules" + + +def test_text_blank_blank(): + options = main.parse_opts(["--front", "blank", "--back", "blank"]) + assert options.text_front == "blank" + assert options.text_back == "blank" + + +def test_text_blank_card(): + options = main.parse_opts(["--front", "blank", "--back", "card"]) + assert options.text_front == "blank" + assert options.text_back == "card" + + +def test_text_blank_none(): + options = main.parse_opts(["--front", "blank", "--back", "none"]) + assert options.text_front == "blank" + assert options.text_back == "none" + + +#################### +# Card Tab Tests +#################### +# --tab_name_align left + + +def test_tab_left_left(): + options = main.parse_opts(["--tab-name-align", "left", "--tab-side", "left"]) + assert options.tab_name_align == "left" + assert options.tab_side == "left" + main.calculate_layout(options) + assert options.tab_name_align == "left" + assert options.tab_side == "left" + + +def test_tab_left_right(): + options = main.parse_opts(["--tab-name-align", "left", "--tab-side", "right"]) + assert options.tab_name_align == "left" + assert options.tab_side == "right" + main.calculate_layout(options) + assert options.tab_name_align == "left" + assert options.tab_side == "right" + + +def test_tab_left_leftalt(): + options = main.parse_opts( + ["--tab-name-align", "left", "--tab-side", "left-alternate"] + ) + assert options.tab_name_align == "left" + assert options.tab_side == "left-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "left" + assert options.tab_side == "left-alternate" + + +def test_tab_left_rightalt(): + options = main.parse_opts( + ["--tab-name-align", "left", "--tab-side", "right-alternate"] + ) + assert options.tab_name_align == "left" + assert options.tab_side == "right-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "left" + assert options.tab_side == "right-alternate" + + +def test_tab_left_full(): + options = main.parse_opts(["--tab-name-align", "left", "--tab-side", "full"]) + assert options.tab_name_align == "left" + assert options.tab_side == "full" + main.calculate_layout(options) + assert options.tab_name_align == "left" + assert options.tab_side == "full" + + # --tab_name_align right + + +def test_tab_right_left(): + options = main.parse_opts(["--tab-name-align", "right", "--tab-side", "left"]) + assert options.tab_name_align == "right" + assert options.tab_side == "left" + main.calculate_layout(options) + assert options.tab_name_align == "right" + assert options.tab_side == "left" + + +def test_tab_right_right(): + options = main.parse_opts(["--tab-name-align", "right", "--tab-side", "right"]) + assert options.tab_name_align == "right" + assert options.tab_side == "right" + main.calculate_layout(options) + assert options.tab_name_align == "right" + assert options.tab_side == "right" + + +def test_tab_right_leftalt(): + options = main.parse_opts( + ["--tab-name-align", "right", "--tab-side", "left-alternate"] + ) + assert options.tab_name_align == "right" + assert options.tab_side == "left-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "right" + assert options.tab_side == "left-alternate" + + +def test_tab_right_rightalt(): + options = main.parse_opts( + ["--tab-name-align", "right", "--tab-side", "right-alternate"] + ) + assert options.tab_name_align == "right" + assert options.tab_side == "right-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "right" + assert options.tab_side == "right-alternate" + + +def test_tab_right_full(): + options = main.parse_opts(["--tab-name-align", "right", "--tab-side", "full"]) + assert options.tab_name_align == "right" + assert options.tab_side == "full" + main.calculate_layout(options) + assert options.tab_name_align == "right" + assert options.tab_side == "full" + + +# --tab_name_align edge + + +def test_tab_edge_left(): + options = main.parse_opts(["--tab-name-align", "edge", "--tab-side", "left"]) + assert options.tab_name_align == "edge" + assert options.tab_side == "left" + main.calculate_layout(options) + assert options.tab_name_align == "edge" + assert options.tab_side == "left" + + +def test_tab_edge_right(): + options = main.parse_opts(["--tab-name-align", "edge", "--tab-side", "right"]) + assert options.tab_name_align == "edge" + assert options.tab_side == "right" + main.calculate_layout(options) + assert options.tab_name_align == "edge" + assert options.tab_side == "right" + + +def test_tab_edge_leftalt(): + options = main.parse_opts( + ["--tab-name-align", "edge", "--tab-side", "left-alternate"] + ) + assert options.tab_name_align == "edge" + assert options.tab_side == "left-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "edge" + assert options.tab_side == "left-alternate" + + +def test_tab_edge_rightalt(): + options = main.parse_opts( + ["--tab-name-align", "edge", "--tab-side", "right-alternate"] + ) + assert options.tab_name_align == "edge" + assert options.tab_side == "right-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "edge" + assert options.tab_side == "right-alternate" + + +def test_tab_edge_full(): + options = main.parse_opts(["--tab-name-align", "edge", "--tab-side", "full"]) + assert options.tab_name_align == "edge" + assert options.tab_side == "full" + options = main.clean_opts(options) + main.calculate_layout(options) + assert options.tab_name_align == "left" # special check for odd condition + assert options.tab_side == "full" + + # --tab_name_align centre + + +def test_tab_centre_left(): + options = main.parse_opts(["--tab-name-align", "centre", "--tab-side", "left"]) + assert options.tab_name_align == "centre" + assert options.tab_side == "left" + main.calculate_layout(options) + assert options.tab_name_align == "centre" + assert options.tab_side == "left" + + +def test_tab_centre_right(): + options = main.parse_opts(["--tab-name-align", "centre", "--tab-side", "right"]) + assert options.tab_name_align == "centre" + assert options.tab_side == "right" + main.calculate_layout(options) + assert options.tab_name_align == "centre" + assert options.tab_side == "right" + + +def test_tab_centre_leftalt(): + options = main.parse_opts( + ["--tab-name-align", "centre", "--tab-side", "left-alternate"] + ) + assert options.tab_name_align == "centre" + assert options.tab_side == "left-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "centre" + assert options.tab_side == "left-alternate" + + +def test_tab_centre_rightalt(): + options = main.parse_opts( + ["--tab-name-align", "centre", "--tab-side", "right-alternate"] + ) + assert options.tab_name_align == "centre" + assert options.tab_side == "right-alternate" + main.calculate_layout(options) + assert options.tab_name_align == "centre" + assert options.tab_side == "right-alternate" + + +def test_tab_centre_full(): + options = main.parse_opts(["--tab-name-align", "centre", "--tab-side", "full"]) + assert options.tab_name_align == "centre" + assert options.tab_side == "full" + main.calculate_layout(options) + assert options.tab_name_align == "centre" + assert options.tab_side == "full" + + +# --tab_name_align center. Just do one since this is an alias to centre + + +def test_tab_center_left(): + options = main.parse_opts(["--tab-name-align", "center", "--tab-side", "left"]) + assert options.tab_name_align == "center" + assert options.tab_side == "left" + options = main.clean_opts(options) + main.calculate_layout(options) + assert options.tab_name_align == "centre" # check for change in value + assert options.tab_side == "left" diff --git a/tools/add_language.py b/tools/add_language.py index a364ba6..d432854 100644 --- a/tools/add_language.py +++ b/tools/add_language.py @@ -7,8 +7,8 @@ import io import csv from shutil import copyfile -LANGUAGE_DEFAULT = 'en_us' # default language, which takes priority -LANGUAGE_XX = 'xx' # language for starting a translation +LANGUAGE_DEFAULT = "en_us" # default language, which takes priority +LANGUAGE_XX = "xx" # language for starting a translation card_db_dir = os.path.join("..", "domdiv", "card_db") # directory of card data output_dir = os.path.join(".", "card_db") # directory for output data @@ -25,23 +25,24 @@ else: def unicode_csv_reader(utf8_data, dialect=csv.excel, **kwargs): csv_reader = csv.reader(utf8_data, dialect=dialect, **kwargs) for row in csv_reader: - yield [cell.decode('iso-8859-15') for cell in row] + yield [cell.decode("iso-8859-15") for cell in row] def get_json_data(json_file_path): # Read in the json from the specified file - with codecs.open(json_file_path, 'r', 'utf-8') as json_file: + with codecs.open(json_file_path, "r", "utf-8") as json_file: data = json.load(json_file) assert data, "Could not load json at: '%r' " % json_file_path return data -def json_dict_entry(entry, separator=''): +def json_dict_entry(entry, separator=""): # Return a nicely formated json dict entry. # It does not include the enclosing {} and removes trailing white space json_data = json.dumps(entry, indent=4, ensure_ascii=False, sort_keys=True) json_data = json_data.strip( - '{}').rstrip() # Remove outer{} and then trailing whitespace + "{}" + ).rstrip() # Remove outer{} and then trailing whitespace return separator + json_data @@ -52,7 +53,7 @@ def find_index(items, find): return None -reader = unicode_csv_reader(open(crossReference + '.csv')) +reader = unicode_csv_reader(open(crossReference + ".csv")) cards = list(reader) headers = cards[0] @@ -63,14 +64,15 @@ lang_dir = os.path.join(output_dir, LANGUAGE_NEW) if not os.path.exists(lang_dir): os.makedirs(lang_dir) -for f in ['bonuses_', 'cards_', 'sets_', 'types_']: +for f in ["bonuses_", "cards_", "sets_", "types_"]: copyfile( - os.path.join(card_db_dir, LANGUAGE_XX, f + LANGUAGE_XX + '.json'), - os.path.join(output_dir, LANGUAGE_NEW, f + LANGUAGE_NEW + '.json')) + os.path.join(card_db_dir, LANGUAGE_XX, f + LANGUAGE_XX + ".json"), + os.path.join(output_dir, LANGUAGE_NEW, f + LANGUAGE_NEW + ".json"), + ) lang_index = find_index(headers, LANGUAGE_NEW) -card_index = find_index(headers, 'card_tag') +card_index = find_index(headers, "card_tag") if lang_index is None or card_index is None: print("Cound not find new language '", LANGUAGE_NEW, "' in the CrossReference file") @@ -93,8 +95,10 @@ else: if cardlist: with io.open( - os.path.join(output_dir, LANGUAGE_NEW, "cards_" + LANGUAGE_NEW + ".json"), 'w', - encoding='utf-8') as lang_out: + os.path.join(output_dir, LANGUAGE_NEW, "cards_" + LANGUAGE_NEW + ".json"), + "w", + encoding="utf-8", + ) as lang_out: lang_out.write("{") # Start of set sep = "" @@ -104,9 +108,9 @@ if cardlist: data = lang_data[card] if card in cardlist: # Have a new name, so update name - data['name'] = cardlist[card] + data["name"] = cardlist[card] fields = [u"description", u"extra"] # but no u"name" - data['untranslated'] = ', '.join(fields) + data["untranslated"] = ", ".join(fields) lang_out.write(json_dict_entry({card: data}, sep)) sep = "," lang_out.write("\n}\n") # End of Set diff --git a/tools/convert_csv.py b/tools/convert_csv.py index 2718fb2..23a5f08 100644 --- a/tools/convert_csv.py +++ b/tools/convert_csv.py @@ -6,35 +6,43 @@ import json converted = [] -typemap = {'Aktion': 'Action', - 'Geld': 'Treasure', - 'Fluch': 'Curse', - 'Punkte': 'Victory', - 'Reaktion': 'Reaction', - 'Angriff': 'Attack', - 'Dauer': 'Duration', - 'Plündern': 'Looter', - 'Ritter': 'Knight', - 'Ruine': 'Ruins', - 'Unterschlupf': 'Shelter', - 'Reisender': 'Traveller', - 'Reserve': 'Reserve'} +typemap = { + "Aktion": "Action", + "Geld": "Treasure", + "Fluch": "Curse", + "Punkte": "Victory", + "Reaktion": "Reaction", + "Angriff": "Attack", + "Dauer": "Duration", + "Plündern": "Looter", + "Ritter": "Knight", + "Ruine": "Ruins", + "Unterschlupf": "Shelter", + "Reisender": "Traveller", + "Reserve": "Reserve", +} -with open(sys.argv[1], 'U') as csvfile: +with open(sys.argv[1], "U") as csvfile: reader = csv.DictReader(csvfile) for row in reader: - if not row['Typ']: + if not row["Typ"]: continue # row = {k: v.decode('ISO-8859-2').encode('utf-8') if type(v) == str else v for k, v in row.iteritems()} # print chardet.detect(row['Kartentext']) - if 'Ritter' in row['Typ'] and row['Kartenname'] != 'Ritter': + if "Ritter" in row["Typ"] and row["Kartenname"] != "Ritter": continue - converted_row = {'name': row['Kartenname'], - 'cost': row['Kosten'], - 'cardset': row['Edition'], - 'description': row['Kartentext'], - 'extra': row['Lange Erklärung'], - 'types': [typemap[t.strip()] for t in row['Typ'].split('/') if not t.strip() == 'Ritter'], - 'potcost': row.get('potcost', 0)} + converted_row = { + "name": row["Kartenname"], + "cost": row["Kosten"], + "cardset": row["Edition"], + "description": row["Kartentext"], + "extra": row["Lange Erklärung"], + "types": [ + typemap[t.strip()] + for t in row["Typ"].split("/") + if not t.strip() == "Ritter" + ], + "potcost": row.get("potcost", 0), + } converted.append(converted_row) -json.dump(converted, open(sys.argv[2], 'wb'), indent=True) +json.dump(converted, open(sys.argv[2], "wb"), indent=True) diff --git a/tools/update_language.py b/tools/update_language.py index 810d914..24a2109 100644 --- a/tools/update_language.py +++ b/tools/update_language.py @@ -21,8 +21,8 @@ import argparse import six -LANGUAGE_DEFAULT = 'en_us' # default language, which takes priority -LANGUAGE_XX = 'xx' # language for starting a translation +LANGUAGE_DEFAULT = "en_us" # default language, which takes priority +LANGUAGE_XX = "xx" # language for starting a translation def get_lang_dirs(path): @@ -39,20 +39,21 @@ def get_lang_dirs(path): def get_json_data(json_file_path): - print(('reading {}'.format(json_file_path))) + print(("reading {}".format(json_file_path))) # Read in the json from the specified file - with codecs.open(json_file_path, 'r', 'utf-8') as json_file: + with codecs.open(json_file_path, "r", "utf-8") as json_file: data = json.load(json_file) assert data, "Could not load json at: '%r' " % json_file_path return data -def json_dict_entry(entry, separator=''): +def json_dict_entry(entry, separator=""): # Return a nicely formated json dict entry. # It does not include the enclosing {} and removes trailing white space json_data = json.dumps(entry, indent=4, ensure_ascii=False, sort_keys=True) json_data = json_data.strip( - '{}').rstrip() # Remove outer{} and then trailing whitespace + "{}" + ).rstrip() # Remove outer{} and then trailing whitespace return separator + json_data @@ -60,6 +61,7 @@ def json_dict_entry(entry, separator=''): # see: http://stackoverflow.com/questions/1143671/python-sorting-list-of-dictionaries-by-multiple-keys def multikeysort(items, columns): from operator import itemgetter + for c in columns[::-1]: items = sorted(items, key=itemgetter(c)) return items @@ -104,18 +106,19 @@ def main(args): type_data = get_json_data(os.path.join(args.card_db_dir, "types_db.json")) # Sort the cards by cardset_tags, then card_tag - sorted_type_data = multikeysort(type_data, ['card_type']) + sorted_type_data = multikeysort(type_data, ["card_type"]) with io.open( - os.path.join(args.output_dir, "types_db.json"), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, "types_db.json"), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("[")) # Start of list sep = "" for type in sorted_type_data: # Collect all the individual types - type_parts = list(set(type['card_type']) | set(type_parts)) - lang_out.write(sep + json.dumps( - type, indent=4, ensure_ascii=False, sort_keys=True)) + type_parts = list(set(type["card_type"]) | set(type_parts)) + lang_out.write( + sep + json.dumps(type, indent=4, ensure_ascii=False, sort_keys=True) + ) sep = "," lang_out.write(six.u("\n]\n")) # End of List @@ -134,15 +137,16 @@ def main(args): label_data = get_json_data(os.path.join(args.card_db_dir, "labels_db.json")) with io.open( - os.path.join(args.output_dir, "labels_db.json"), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, "labels_db.json"), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("[")) # Start of list sep = "" for label in label_data: # Collect all the individual types - all_labels = list(set(label['names']) | set(all_labels)) - lang_out.write(sep + json.dumps( - label, indent=4, ensure_ascii=False, sort_keys=True)) + all_labels = list(set(label["names"]) | set(all_labels)) + lang_out.write( + sep + json.dumps(label, indent=4, ensure_ascii=False, sort_keys=True) + ) sep = "," lang_out.write(six.u("\n]\n")) # End of List @@ -168,8 +172,8 @@ def main(args): lang_type_data = {} with io.open( - os.path.join(args.output_dir, lang, lang_file), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, lang, lang_file), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("{")) # Start of types sep = "" used = [] @@ -189,10 +193,7 @@ def main(args): # Now keep any unused values just in case needed in the future for key in lang_type_data: if key not in used: - lang_out.write( - json_dict_entry({ - key: lang_type_data[key] - }, sep)) + lang_out.write(json_dict_entry({key: lang_type_data[key]}, sep)) sep = "," lang_out.write(six.u("\n}\n")) # End of Types @@ -207,7 +208,7 @@ def main(args): ########################################################################### cards = [] groups = [] - super_groups = [u'events', u'landmarks'] + super_groups = [u"events", u"landmarks"] # Get the card data card_data = get_json_data(os.path.join(args.card_db_dir, "cards_db.json")) @@ -216,26 +217,27 @@ def main(args): for card in card_data: card["cardset_tags"].sort() # But put all the base cards together by moving to front of the list - if 'base' in card["cardset_tags"]: - card["cardset_tags"].remove('base') - card["cardset_tags"].insert(0, 'base') + if "base" in card["cardset_tags"]: + card["cardset_tags"].remove("base") + card["cardset_tags"].insert(0, "base") # Sort the cards by cardset_tags, then card_tag - sorted_card_data = multikeysort(card_data, ['cardset_tags', 'card_tag']) + sorted_card_data = multikeysort(card_data, ["cardset_tags", "card_tag"]) with io.open( - os.path.join(args.output_dir, "cards_db.json"), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, "cards_db.json"), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("[")) # Start of list sep = "" for card in sorted_card_data: - if card['card_tag'] not in cards: - cards.append(card['card_tag']) - if 'group_tag' in card: - if card['group_tag'] not in groups: - groups.append(card['group_tag']) - lang_out.write(sep + json.dumps( - card, indent=4, ensure_ascii=False, sort_keys=True)) + if card["card_tag"] not in cards: + cards.append(card["card_tag"]) + if "group_tag" in card: + if card["group_tag"] not in groups: + groups.append(card["group_tag"]) + lang_out.write( + sep + json.dumps(card, indent=4, ensure_ascii=False, sort_keys=True) + ) sep = "," lang_out.write(six.u("\n]\n")) # End of List @@ -267,8 +269,8 @@ def main(args): # Process the file with io.open( - os.path.join(args.output_dir, lang, lang_file), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, lang, lang_file), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("{")) # Start of set sep = "" fields = [u"description", u"extra", u"name"] @@ -282,19 +284,20 @@ def main(args): lang_data[card]["extra"] = "" lang_data[card]["name"] = card lang_data[card]["description"] = "" - lang_data[card]["untranslated"] = ', '.join(fields) + lang_data[card]["untranslated"] = ", ".join(fields) lang_default = lang_data else: # All other languages should get the default languages' text lang_data[card]["extra"] = lang_default[card]["extra"] lang_data[card]["name"] = lang_default[card]["name"] lang_data[card]["description"] = lang_default[card][ - "description"] - lang_data[card]["untranslated"] = ', '.join(fields) + "description" + ] + lang_data[card]["untranslated"] = ", ".join(fields) else: # Card exists, figure out what needs updating (don't update default language) if lang != LANGUAGE_DEFAULT: - if 'untranslated' in lang_data[card]: + if "untranslated" in lang_data[card]: # Has an 'untranslated' field. Process accordingly if not lang_data[card]["untranslated"].strip(): # It is empty, so just remove it @@ -302,31 +305,33 @@ def main(args): else: # If a field remains untranslated, then replace with the default languages copy for field in fields: - if field in lang_data[card]['untranslated']: - lang_data[card][field] = lang_default[ - card][field] + if field in lang_data[card]["untranslated"]: + lang_data[card][field] = lang_default[card][ + field + ] else: # Need to create the 'untranslated' field and update based upon existing fields untranslated = [] for field in fields: if field not in lang_data[card]: - lang_data[card][field] = lang_default[card][ - field] + lang_data[card][field] = lang_default[card][field] untranslated.append(field) if untranslated: # only add if something is still needing translation - lang_data[card]["untranslated"] = ', '.join( - untranslated) + lang_data[card]["untranslated"] = ", ".join( + untranslated + ) lang_out.write(json_dict_entry({card: lang_data[card]}, sep)) - lang_data[card]['used'] = True + lang_data[card]["used"] = True sep = "," # Now keep any unused values just in case needed in the future for key in lang_data: - if 'used' not in lang_data[key]: + if "used" not in lang_data[key]: lang_data[key][ - "untranslated"] = "Note: This card is currently not used." + "untranslated" + ] = "Note: This card is currently not used." lang_out.write(json_dict_entry({key: lang_data[key]}, sep)) sep = "," lang_out.write(six.u("\n}\n")) # End of Set @@ -342,8 +347,8 @@ def main(args): set_data = get_json_data(os.path.join(args.card_db_dir, lang_file)) with io.open( - os.path.join(args.output_dir, lang_file), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, lang_file), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("{")) # Start of set sep = "" sets = [] @@ -376,8 +381,8 @@ def main(args): else: lang_set_data = {} with io.open( - os.path.join(args.output_dir, lang, lang_file), 'w', - encoding='utf-8') as lang_out: + os.path.join(args.output_dir, lang, lang_file), "w", encoding="utf-8" + ) as lang_out: lang_out.write(six.u("{")) # Start of set sep = "" @@ -386,38 +391,33 @@ def main(args): lang_set_data[s] = {} if lang == LANGUAGE_DEFAULT: lang_set_data[s]["set_name"] = s.title() - lang_set_data[s]["text_icon"] = set_data[s][ - "text_icon"] - if 'short_name' in set_data[s]: - lang_set_data[s]["short_name"] = set_data[s][ - "short_name"] - if 'set_text' in set_data[s]: - lang_set_data[s]["set_text"] = set_data[s][ - "set_text"] + lang_set_data[s]["text_icon"] = set_data[s]["text_icon"] + if "short_name" in set_data[s]: + lang_set_data[s]["short_name"] = set_data[s]["short_name"] + if "set_text" in set_data[s]: + lang_set_data[s]["set_text"] = set_data[s]["set_text"] else: - lang_set_data[s]["set_name"] = lang_default[s][ - "set_name"] - lang_set_data[s]["text_icon"] = lang_default[s][ - "text_icon"] - if 'short_name' in lang_default[s]: + lang_set_data[s]["set_name"] = lang_default[s]["set_name"] + lang_set_data[s]["text_icon"] = lang_default[s]["text_icon"] + if "short_name" in lang_default[s]: lang_set_data[s]["short_name"] = lang_default[s][ - "short_name"] - if 'set_text' in lang_default[s]: - lang_set_data[s]["set_text"] = lang_default[s][ - "set_text"] + "short_name" + ] + if "set_text" in lang_default[s]: + lang_set_data[s]["set_text"] = lang_default[s]["set_text"] else: if lang != LANGUAGE_DEFAULT: for x in lang_default[s]: - if x not in lang_set_data[s] and x != 'used': + if x not in lang_set_data[s] and x != "used": lang_set_data[s][x] = lang_default[s][x] lang_out.write(json_dict_entry({s: lang_set_data[s]}, sep)) - lang_set_data[s]['used'] = True + lang_set_data[s]["used"] = True sep = "," # Now keep any unused values just in case needed in the future for key in lang_set_data: - if 'used' not in lang_set_data[key]: + if "used" not in lang_set_data[key]: lang_out.write(json_dict_entry({key: lang_set_data[key]}, sep)) sep = "," @@ -436,30 +436,43 @@ def main(args): fromLanguage = LANGUAGE_DEFAULT copyfile( - os.path.join(args.card_db_dir, fromLanguage, "bonuses_" + fromLanguage + ".json"), - os.path.join(args.output_dir, lang, "bonuses_" + lang + ".json")) + os.path.join( + args.card_db_dir, fromLanguage, "bonuses_" + fromLanguage + ".json" + ), + os.path.join(args.output_dir, lang, "bonuses_" + lang + ".json"), + ) ########################################################################### # translation.txt ########################################################################### copyfile( os.path.join(args.card_db_dir, "translation.md"), - os.path.join(args.output_dir, "translation.md")) + os.path.join(args.output_dir, "translation.md"), + ) # Since xx is the starting point for new translations, # make sure xx has the latest copy of translation.txt copyfile( os.path.join(args.card_db_dir, LANGUAGE_XX, "translation.txt"), - os.path.join(args.output_dir, LANGUAGE_XX, "translation.txt")) + os.path.join(args.output_dir, LANGUAGE_XX, "translation.txt"), + ) -if __name__ == '__main__': +if __name__ == "__main__": parser = argparse.ArgumentParser() - parser.add_argument('--card_db_dir', default=os.path.join(os.path.dirname(os.path.abspath(__file__)), - "..", "domdiv", "card_db"), - help='directory of card data') - parser.add_argument('--output_dir', - default=os.path.join(os.path.dirname(os.path.abspath(__file__)), ".", "card_db"), - help='directory for output data') + parser.add_argument( + "--card_db_dir", + default=os.path.join( + os.path.dirname(os.path.abspath(__file__)), "..", "src", "domdiv", "card_db" + ), + help="directory of card data", + ) + parser.add_argument( + "--output_dir", + default=os.path.join( + os.path.dirname(os.path.abspath(__file__)), ".", "card_db" + ), + help="directory for output data", + ) args = parser.parse_args() main(args)