precommit git hooks, rearrange package structure (#251)
* precommit hooks and changes because of these * mv package into src dir * add requirements file, clean up setup reqs, add precommit to CI
6
.gitignore
vendored
@ -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/
|
||||
.mypy_cache/
|
||||
|
||||
20
.pre-commit-config.yaml
Normal file
@ -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]
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
12
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 <https://boardgamegeek.com/thread/926575/web-page-generate-tabbed-dividers> or file issues on github (<https://github.com/sumpfork/dominiontabs/issues>).
|
||||
|
||||
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.
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
import pkg_resources
|
||||
__version__ = pkg_resources.require('domdiv')[0].version
|
||||
@ -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.
|
||||
@ -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'
|
||||
5
requirements.in
Normal file
@ -0,0 +1,5 @@
|
||||
reportlab
|
||||
Pillow
|
||||
pre-commit
|
||||
pytest
|
||||
six
|
||||
25
requirements.txt
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
24
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.",
|
||||
)
|
||||
|
||||
3
src/domdiv/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
import pkg_resources
|
||||
|
||||
__version__ = pkg_resources.require("domdiv")[0].version
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"exclude": [
|
||||
"Token",
|
||||
"Tokens",
|
||||
"Tokens",
|
||||
"Marker"
|
||||
],
|
||||
"include": [
|
||||
@ -16,4 +16,4 @@
|
||||
"Punkt",
|
||||
"Punkte"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -18,4 +18,4 @@
|
||||
"Villagers",
|
||||
"<VP>"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -19,4 +19,4 @@
|
||||
"Actions",
|
||||
"Action"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -13,4 +13,4 @@
|
||||
"Azioni",
|
||||
"Azione"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -14,4 +14,4 @@
|
||||
"Acties",
|
||||
"Actie"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -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`,
|
||||
* `+ <VP>`
|
||||
|
||||
- When possible, bonuses should be listed vertically and centered. Examples:
|
||||
|
||||
* `+1 Card<br>+1 Action<br>+1 Buy<br>+1 Coin<br>+2 <VP><n>`
|
||||
* `+1 Card\n+1 Action\n+1 Buy\n+1 Coin\n+2 <VP>\n`
|
||||
|
||||
|
||||
The `description` field by default is centered. `<br>`, `<n>`, 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":
|
||||
|
||||
`<left><u>Settlers</u>:<n>+1 Card<br>+1 Action<n>Look through your discard pile.
|
||||
`<left><u>Settlers</u>:<n>+1 Card<br>+1 Action<n>Look through your discard pile.
|
||||
You may reveal a Copper from it and put it into your hand.<n>
|
||||
<left><u>Bustling Village</u>:<n><center>+1 Card<br>+3 Actions<n>
|
||||
Look through your discard pile. You may reveal a Settlers from it and put it into your hand.`
|
||||
|
||||
@ -18,4 +18,4 @@
|
||||
"Villagers",
|
||||
"<VP>"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -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": "<left><u>Settlers</u>:<n>+1 Card<br>+1 Action<n>Look through your discard pile. You may reveal a Copper from it and put it into your hand.<n><left><u>Bustling Village</u>:<n><center>+1 Card<br>+3 Actions<n>Look through your discard pile. You may reveal a Settlers from it and put it into your hand."
|
||||
|
||||
@ -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, '<b>\\1</b>', text)
|
||||
text = re.sub(regex, "<b>\\1</b>", 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
|
||||
# (?!\<b\>) 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)((?!\<b\>)" + 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
|
||||
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 925 KiB After Width: | Height: | Size: 925 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 218 KiB After Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |