1
0
Fork 0
mirror of https://github.com/shlomif/PySolFC.git synced 2025-04-15 02:54:09 -04:00

Compare commits

...

18 commits

Author SHA1 Message Date
Juhani Numminen
7255ad9e68 macOS: Update travis to python 3.9 2020-10-12 23:35:15 +03:00
Juhani Numminen
451700aefa macOS: Create PySolFC.dmg for convenient installation 2020-10-12 23:35:15 +03:00
Juhani Numminen
97e981d900 macOS: ensure the application window is shown
py2app's "argv_emulation" feature prevents the Tkinter window from being shown
when PySolFC.app is launched.

This did not affect launching pysol.py using Terminal on macOS.

Solution found here: https://stackoverflow.com/questions/12992316/tkinter-py2app-created-application-doesnt-show-window-on-initial-launch
2020-10-12 23:35:15 +03:00
Juhani Numminen
d3faa78e75 Prune pysollib.macosx; it no longer had any effect 2020-10-12 23:35:15 +03:00
Juhani Numminen
07aac001b7 Clarify where a COPYRIGHT file should exist 2020-10-11 16:47:16 +03:00
Juhani Numminen
278b3261d9 Optimize cardsetparser
Apply the EAFP principle:
Regex matching was just doing extra the work because int() will check that
its argument is suitable in any case.

EAFP as in https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python
2020-10-11 16:27:43 +03:00
Juhani Numminen
755b1d51d3 Remove file that shouldn't be there 2020-10-11 14:38:27 +03:00
Shlomi Fish
cb0ddeeccd use https:// link instead of mailto:
The mailto: link is available there
2020-10-11 13:27:05 +03:00
Shlomi Fish
dda2f3b520 revise some confusing phrasing 2020-10-11 13:23:14 +03:00
Shlomi Fish
d145642a9b Rename variables to make them more descriptive.
We used "lines_list" instead of "line" in singular. "list" is
the ADT ( https://en.wikipedia.org/wiki/Abstract_data_type )
rather than its python class.
2020-10-11 13:02:01 +03:00
Juhani Numminen
12601364dc Invoke init_tile() only when tile is used 2020-10-10 21:23:35 +03:00
Juhani Numminen
0be465dea1 Add error message for a missing card back (#185) 2020-10-10 21:22:58 +03:00
Neelix57
0f15613a15 fix cardset tutorial 2020-10-10 21:22:07 +03:00
Neelix57
1b14baf856 modify cardset tutorial 2020-10-10 21:21:52 +03:00
Juhani Numminen
da5b85c064 contrib/install-pysolfc.sh: pip install pygame for sound output (#180) 2020-10-08 15:10:22 +03:00
Juhani Numminen
a8a262a68c AppVeyor fix: change py2exe to pyinstaller
py2exe seems abandoned and still requires python < 3.4
while attrs does not support such an old python version anymore.

* https://ci.appveyor.com/project/shlomif/pysolfc/builds/35127928

To accommodate pyinstaller's directory layout, dist was changed to
dist/pysol in scripts/create_iss.py.

scripts/build.bat had become unmaintained and outdated.
2020-10-08 15:04:36 +03:00
Shlomi Fish
95a0d7d007 refactor/modernize the calls to open()
use "with", flags
2020-10-06 18:43:15 +03:00
Juhani Numminen
bf9ce90a5b Refactor cardset config.txt parser to a new module 2020-10-06 14:35:28 +03:00
27 changed files with 312 additions and 281 deletions

View file

@ -1,23 +1,25 @@
---
environment:
matrix:
- PYTHON: "C:\\PYTHON34"
- PYTHON: "C:\\Python37"
# Shamelessly taken from https://github.com/plicease/Dist-Zilla-PluginBundle-Author-Plicease/blob/master/.appveyor.yml
# Thanks!
install:
- choco install strawberryperl
- copy %PYTHON%\python.exe %PYTHON%\python3.exe
- SET PATH=%PYTHON%;C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
- python3 -mpip install Pillow attrs configobj flake8 flake8-import-order py2exe pycotap pygame pysol-cards random2 setuptools six
- SET PATH=%PYTHON%;%PYTHON%\Scripts;C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
- python3 -mpip install Pillow attrs configobj flake8 flake8-import-order
pycotap pygame pyinstaller pysol-cards random2 setuptools six
- perl -v
- copy C:\msys64\mingw64\bin\mingw32-make.exe C:\msys64\mingw64\bin\make.exe
- SET PATH=C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%
- SET PERL5LIB=C:/_P5/lib/perl5
- SET PERL_LOCAL_LIB_ROOT=C:/_P5
- SET PERL_MB_OPT=--install_base C:/_P5
- SET PERL_MM_OPT=INSTALL_BASE=C:/_P5
- perl -v
- cpanm --notest Code::TidyAll::Plugin::Flake8 File::Find::Object Perl::Tidy Task::FreecellSolver::Testing Test::Code::TidyAll Test::TrailingSpace
- cpanm --notest Code::TidyAll::Plugin::Flake8 File::Find::Object
Perl::Tidy Task::FreecellSolver::Testing Test::Code::TidyAll
Test::TrailingSpace
- echo %PATH%
build: off
test_script:
@ -30,13 +32,14 @@ test_script:
- gmake rules
- gmake pot
- gmake mo
- python3 setup.py py2exe
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/PySolFC-Cardsets-2.0/PySolFC-Cardsets-2.0.tar.bz2/download -FileName cardsets.tar.bz2
- tar xf cardsets.tar.bz2
- xargs -ta scripts\cardsets_to_bundle -I file cp -rt dist\data\ PySolFC-Cardsets-2.0\file
- pyinstaller pysol.py --windowed --icon=data\pysol.ico
- python3 setup.py install_data -d dist\pysol
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySolFC-Cardsets/minimal/PySolFC-Cardsets--Minimal-2.0.1.tar.xz/download -FileName cardsets.tar.xz
- 7z x cardsets.tar.xz -so | 7z x -si -ttar
- mv PySolFC-Cardsets--Minimal-2.0.1/cardset-* dist/pysol/data
- appveyor DownloadFile https://sourceforge.net/projects/pysolfc/files/PySol-Music/PySol-Music-4.50/pysol-music-4.50.tar.xz/download -FileName music.tar.xz
- 7z x music.tar.xz -so | 7z x -si -ttar
- move pysol-music-4.50\data\music dist\data\music
- move pysol-music-4.50\data\music dist\pysol\data\music
# - ps: |
# $apiUrl = 'https://ci.appveyor.com/api'
# $project = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/shlomif/fc-solve"
@ -48,8 +51,8 @@ test_script:
- SET FC_SOLVE_VER=5.20.0
- appveyor DownloadFile https://netix.dl.sourceforge.net/project/fc-solve/fc-solve/DO-NOT-USE--fc-solve-for-pysol/fc-solve-for-pysol--v%FC_SOLVE_VER%.zip -FileName fc-solve.zip
- 7z x fc-solve.zip
- move fcs-pysol dist\freecell-solver
- 7z a -r pysol_win_dist.7z dist\
- move fcs-pysol dist\pysol\freecell-solver
- 7z a -r pysol_win_dist.7z dist\pysol\
- SET PYTHONPATH=%cd%
- python3 scripts\create_iss.py
- appveyor DownloadFile https://download.microsoft.com/download/C/6/D/C6D0FD4E-9E53-4897-9B91-836EBA2AACD3/vcredist_x86.exe -FileName vcredist_x86.exe
@ -58,7 +61,7 @@ test_script:
artifacts:
- path: pysol_win_dist.7z
name: pysol_win_dist
- path: dist\PySolFC_*_setup.exe
- path: dist\pysol\PySolFC_*_setup.exe
name: pysol_win_installer
cache:
# - C:\_P5 -> .appveyor.yml

View file

@ -11,7 +11,7 @@ deploy:
api_key:
secure: SrKnXigL/oUHNbqpbGx0DB1o+LAEkfPA2QTBllXxg4V+1vGAHBT9FRecp8Do+no/zSPRttH+sPDEPBXMMAV0BWVKKw5Mxas/S5ulVkNdfxpTq1bKjI3EjZbVsS1zZlHe0P77TDFDAj8zyeiYecBM08suhd9OvScieiPlpFPE1UYp9vvNKaBgc66IRNnIDRBdktW4YLsgvkrpXnxGPy8gGwylsTeOzNs5/r5dzHswGdksJl46kqCIbV+s4/Xcx+BEnfibWzEFZmLQoGKhoukbSis3YXGIlERcgiVU6v7S2D4wbwUXSAKOj/Io7z/88Co2P3Qbm538kf/pjeR9+DaM1HsHQQcL0detCjjLog+ekKr2fM00QI1yRmqOiZtuXxTMpneYX73EBmPt4la4rjKmnlhS+NTxrynHcPZD8QopCPvoZ3sUD6dQCrbi8kcGxe13srfdJ3KjuWZXdedLIOgNELbj5o6GNivsanWna59yoJzChC5/H5Jjllncvzbp56TZfEkM1NJkE84jjSS8Sn2KLXjD0woHIsuUSkRNExrCt/6QmIub/QxZPUhwQ2J0xCv1IJPdd0XvO3gCqasG3UA2Q0OlP172x92ocOV/wm1/4wfoG6v/mn+bX5ZwvrsMmm+r3FKKlM8L3T33yFjMzgG/YMoRN8w7pXUIkdtZK8EEDVg=
# file: dist/PySolFC.app
file: PySolFC.app.tar.xz
file: PySolFC.dmg
on:
repo: shlomif/PySolFC
tags: true
@ -24,8 +24,8 @@ before_install:
mv PySolFC-Cardsets--Minimal-2.0/cardset-* data ;
fi
- if test "$TRAVIS_OS_NAME" = "osx" ; then
PYVER=3.8.2 &&
PYVER_SHORT=3.8 &&
PYVER=3.9.0 &&
PYVER_SHORT=3.9 &&
wget -O python.pkg "https://www.python.org/ftp/python/${PYVER}/python-${PYVER}-macosx10.9.pkg" &&
sudo installer -pkg python.pkg -target / &&
export PATH="/Library/Frameworks/Python.framework/Versions/${PYVER_SHORT}/bin:${PATH}" ;
@ -61,6 +61,11 @@ script:
- export TIDYALL_DATA_DIR="$HOME/tidyall_d"
- bash -x scripts/travis-ci-build
- if test "$TRAVIS_OS_NAME" = "osx" ; then PYTHONPATH="." python3 setup_osx.py py2app ; fi
- if test "$TRAVIS_OS_NAME" = "osx" ; then find . -iname '*.app' ; fi
- if test "$TRAVIS_OS_NAME" = "osx" ; then (cd dist && tar -cvf ../PySolFC.app.tar PySolFC.app/) && xz PySolFC.app.tar ; fi
- if test "$TRAVIS_OS_NAME" = "osx" ; then
create-dmg --volname "Install PySolFC"
--volicon data/PySol.icns
--background html-src/images/pysollogo01.png
--window-size 800 400
--icon PySolFC.app 200 185
--app-drop-link 600 185
PySolFC.dmg dist ; fi

View file

@ -1,5 +1,6 @@
brew "perl"
brew "cpanminus"
brew "create-dmg"
brew "gettext", link: true
brew "gnutls"
brew "jpeg"

View file

@ -7,7 +7,7 @@ include pysol.py setup.py setup_osx.py setup.cfg MANIFEST.in Makefile
include COPYING README.md AUTHORS.md README.android README.kivy
include NEWS.asciidoc
#recursive-include pysollib *.py
include pysollib/*.py pysollib/macosx/*.py
include pysollib/*.py
include pysollib/winsystems/*.py
include pysollib/tk/*.py pysollib/tile/*.py pysollib/pysolgtk/*.py
include pysollib/game/*.py
@ -18,7 +18,7 @@ include data/pysol.desktop
include data/pysolfc.glade
graft data/themes
recursive-exclude data/themes *.py
include scripts/build.bat scripts/create_iss.py scripts/mahjongg_utils.py
include scripts/create_iss.py scripts/mahjongg_utils.py
include scripts/all_games.py scripts/cardset_viewer.py
include scripts/cardconv
include scripts/gen_individual_importing_tests.py

View file

@ -19,7 +19,9 @@ back01.ext;back02.ext;back03.ext
Line 1
------
*$A:* The number of fields in first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)
*$A:* The cardset version number that belongs to the number of fields divided through ";" on the first line (e.g. `.gif;1;78;8,1016` -> `$A=4`)
( *WARNING:* For Mahjongg, $A must always be 6 and the $F field must be included in the line; however, you can put `0` in `$F` if you wish, in that case. )
( *NOTE:* $D and $E are comma separated and count for one field )
@ -154,6 +156,10 @@ You are welcome to send any suggestions to: mailto:neelix570@gmail.com[the Autho
https://github.com/shlomif/PySolFC/issues[PySol FC's GitHub issue tracker] or
https://sourceforge.net/p/pysolfc/_list/tickets[PySol FC's Sourceforge issue tracker].
*NOTE 2:*
You should also place a file called `COPYRIGHT` in the same directory as `config.txt`,
containing the text that can be accessed via `Info/Settings`.
License:
~~~~~~~~
@ -162,3 +168,12 @@ version 3 or later. You can redistribute it as is and/or modify it.
Shlomi Fish, hereby puts his modifications to this document under
https://github.com/shlomif/shlomif-computer-settings/blob/master/shlomif-settings/git/commit-messages/cc0-copyright-disclaimer.txt[CC0 / Public Domain / MIT License / GPL terms]
Credits:
~~~~~~~~
Credits go to:
mailto:andsa@web.de[Andreas Sauer] for clarifying certain points +
https://www.shlomifish.org/[Shlomi Fish] for making some improvements to this tutorial

View file

@ -2,15 +2,15 @@
set -Cefu
: ${PKGTREE:=/usr/local/packages/PySolFC}
PIP=("${PKGTREE}/env/bin/pip" install --no-binary :all:)
PYPROG="$(printf '%s/env/bin/python' "$PKGTREE")"
PIP="${PKGTREE}/env/bin/pip"
PYPROG="${PKGTREE}/env/bin/python"
VERSION="$(env PYTHONPATH=`pwd` "$PYPROG" -c 'from pysollib.settings import VERSION ; print(VERSION)')"
XZBALL="$(printf 'dist/PySolFC-%s.tar.xz' "$VERSION")"
reqs='six random2 pillow'
XZBALL="dist/PySolFC-${VERSION}.tar.xz"
reqs=(pillow pygame random2 six)
make dist
for req in $reqs
do
"${PIP[@]}" "$req"
done
"${PIP[@]}" --upgrade "$XZBALL"
"$PIP" install wheel
"$PIP" install "${reqs[@]}"
"$PIP" install --upgrade "$XZBALL"

View file

@ -1 +0,0 @@
modifications from repoB

View file

@ -519,7 +519,8 @@ class PysolMenubar(PysolMenubarTk):
text += os.linesep
enc = locale.getpreferredencoding()
try:
open(fn, 'a').write(text.encode(enc, 'replace'))
with open(fn, 'at') as fh:
fh.write(text.encode(enc, 'replace'))
except Exception as err:
d = MfxExceptionDialog(
self.top, err,

View file

@ -33,6 +33,7 @@ from pysollib.actions import PysolMenubar
from pysollib.actions import PysolToolbar
from pysollib.app_stat_result import GameStatResult
from pysollib.app_statistics import Statistics
from pysollib.cardsetparser import read_cardset_config
from pysollib.gamedb import GAME_DB, GI, loadGame
from pysollib.help import destroy_help_html, help_about
from pysollib.images import Images, SubsampledImages
@ -53,7 +54,7 @@ from pysollib.pysoltk import SelectCardsetDialogWithPreview
from pysollib.pysoltk import SelectDialogTreeData
from pysollib.pysoltk import destroy_find_card_dialog
from pysollib.pysoltk import loadImage, wm_withdraw
from pysollib.resource import CSI, Cardset, CardsetConfig, CardsetManager
from pysollib.resource import CSI, CardsetManager
from pysollib.resource import Music, MusicManager
from pysollib.resource import Sample, SampleManager
from pysollib.resource import Tile, TileManager
@ -1070,125 +1071,14 @@ Please select a %(correct_type)s type cardset.
# read & parse a cardset config.txt file - see class Cardset in resource.py
def _readCardsetConfig(self, dirname, filename):
with open(filename, "r") as f:
lines = f.readlines()
lines = [line.strip() for line in lines]
if not lines[0].startswith("PySol"):
return None
config = CardsetConfig()
if not self._parseCardsetConfig(config, lines):
# print filename, 'invalid config'
return None
if config.CARDD > self.top.winfo_screendepth():
return None
cs = Cardset()
cs.dir = dirname
cs.update(config.__dict__)
return cs
def _parseCardsetConfig(self, cs, line):
def perr(line, field=None, msg=''):
if not DEBUG:
return
if field:
print_err('_parseCardsetConfig error: line #%d, field #%d %s'
% (line, field, msg))
else:
print_err('_parseCardsetConfig error: line #%d: %s'
% (line, msg))
if len(line) < 6:
perr(1, msg='number of lines')
return 0
# line[0]: magic identifier, possible version information
fields = [f.strip() for f in line[0].split(';')]
if len(fields) >= 2:
m = re.search(r"^(\d+)$", fields[1])
if m:
cs.version = int(m.group(1))
if cs.version >= 3:
if len(fields) < 5:
perr(1, msg='number of fields')
return 0
cs.ext = fields[2]
m = re.search(r"^(\d+)$", fields[3])
if not m:
perr(1, 3, 'not integer')
return 0
cs.type = int(m.group(1))
m = re.search(r"^(\d+)$", fields[4])
if not m:
perr(1, 4, 'not integer')
return 0
cs.ncards = int(m.group(1))
if cs.version >= 4:
if len(fields) < 6:
perr(1, msg='number of fields')
return 0
styles = fields[5].split(",")
for s in styles:
m = re.search(r"^\s*(\d+)\s*$", s)
if not m:
perr(1, 5, 'not integer')
return 0
s = int(m.group(1))
if s not in cs.styles:
cs.styles.append(s)
if cs.version >= 5:
if len(fields) < 7:
perr(1, msg='number of fields')
return 0
m = re.search(r"^(\d+)$", fields[6])
if not m:
perr(1, 6, 'not integer')
return 0
cs.year = int(m.group(1))
if len(cs.ext) < 2 or cs.ext[0] != ".":
perr(1, msg='invalid extention')
return 0
# line[1]: identifier/name
if not line[1]:
perr(2, msg='empty line')
return 0
cs.ident = line[1]
m = re.search(r"^(.*;)?([^;]+)$", cs.ident)
if not m:
perr(2, msg='invalid format')
return 0
cs.name = m.group(2).strip()
# line[2]: CARDW, CARDH, CARDD
m = re.search(r"^(\d+)\s+(\d+)\s+(\d+)", line[2])
if not m:
perr(3, msg='invalid format')
return 0
cs.CARDW, cs.CARDH, cs.CARDD = \
int(m.group(1)), int(m.group(2)), int(m.group(3))
# line[3]: CARD_UP_YOFFSET, CARD_DOWN_YOFFSET,
# SHADOW_XOFFSET, SHADOW_YOFFSET
m = re.search(r"^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)", line[3])
if not m:
perr(4, msg='invalid format')
return 0
cs.CARD_XOFFSET = int(m.group(1))
cs.CARD_YOFFSET = int(m.group(2))
cs.SHADOW_XOFFSET = int(m.group(3))
cs.SHADOW_YOFFSET = int(m.group(4))
# line[4]: default background
back = line[4]
if not back:
perr(5, msg='empty line')
return 0
# line[5]: all available backgrounds
cs.backnames = [f.strip() for f in line[5].split(';')]
if back in cs.backnames:
cs.backindex = cs.backnames.index(back)
else:
cs.backnames.insert(0, back)
cs.backindex = 0
cs = read_cardset_config(dirname, filename)
# set offsets from options.cfg
if cs.ident in self.opt.offsets:
cs.CARD_XOFFSET, cs.CARD_YOFFSET = self.opt.offsets[cs.ident]
# if cs.type != 1: print cs.type, cs.name
return 1
if cs.CARDD > self.top.winfo_screendepth():
return None
return cs
def initCardsets(self):
manager = self.cardset_manager
@ -1232,9 +1122,8 @@ Please select a %(correct_type)s type cardset.
# print '+', cs.name
fnames[cs.name] = 1
else:
print_err('fail _readCardsetConfig: %s %s'
% (d, f))
pass
print_err('failed to parse cardset file: %s'
% f)
except Exception:
# traceback.print_exc()
pass

148
pysollib/cardsetparser.py Normal file
View file

@ -0,0 +1,148 @@
#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
# ---------------------------------------------------------------------------##
#
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
# Copyright (C) 2003 Mt. Hood Playing Card Co.
# Copyright (C) 2005-2009 Skomoroh
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ---------------------------------------------------------------------------##
from pysollib.mfxutil import print_err
from pysollib.resource import Cardset, CardsetConfig
def _perr(line_no, field=None, msg=''):
if field:
print_err('cannot parse cardset config: line #%d, field #%d: %s'
% (line_no, field, msg))
else:
print_err('cannot parse cardset config: line #%d: %s' % (line_no, msg))
def read_cardset_config(dirname, filename):
"""Parse a cardset config file and produce a Cardset object.
This function returns None if any errors occurred.
"""
with open(filename, "rt") as f:
lines_list = f.readlines()
lines_list = [line.strip() for line in lines_list]
if not lines_list[0].startswith("PySol"):
return None
config = parse_cardset_config(lines_list)
if not config:
print_err('invalid cardset: %s' % filename)
return None
cs = Cardset()
cs.dir = dirname
cs.update(config.__dict__)
return cs
def parse_cardset_config(lines_list):
cs = CardsetConfig()
if len(lines_list) < 6:
_perr(1, msg='not enough lines in file')
return None
# lines_list[0]: magic identifier, possible version information
fields = [f.strip() for f in lines_list[0].split(';')]
if len(fields) >= 2:
try:
cs.version = int(fields[1])
except ValueError:
# version 1 is implied
cs.version = 1
if cs.version >= 3:
if len(fields) < 5:
_perr(1, msg='not enough fields')
return None
cs.ext = fields[2]
try:
cs.type = int(fields[3])
except ValueError:
_perr(1, 3, 'not integer')
return None
try:
cs.ncards = int(fields[4])
except ValueError:
_perr(1, 4, 'not integer')
return None
if cs.version >= 4:
if len(fields) < 6:
_perr(1, msg='not enough fields')
return None
try:
styles = (int(s.strip()) for s in fields[5].split(","))
cs.styles = list(set(styles))
except ValueError:
_perr(1, 5, 'not integer')
return None
if cs.version >= 5:
if len(fields) < 7:
_perr(1, msg='not enough fields')
return None
try:
cs.year = int(fields[6])
except ValueError:
_perr(1, 6, 'not integer')
return None
if len(cs.ext) < 2 or cs.ext[0] != ".":
_perr(1, msg='specifies an invalid file extension')
return None
# lines_list[1]: identifier/name
if not lines_list[1]:
_perr(2, msg='unexpected empty line')
return None
cs.ident = lines_list[1]
split_ident = cs.ident.split(';')
if len(split_ident) == 1:
cs.name = cs.ident
elif len(split_ident) == 2:
cs.name = split_ident[1].strip()
else:
_perr(2, msg='invalid format')
return None
# lines_list[2]: CARDW, CARDH, CARDD
try:
cs.CARDW, cs.CARDH, cs.CARDD = (int(x) for x in lines_list[2].split())
except ValueError:
_perr(3, msg='invalid format')
return None
# lines_list[3]: CARD_UP_YOFFSET, CARD_DOWN_YOFFSET,
# SHADOW_XOFFSET, SHADOW_YOFFSET
try:
(cs.CARD_XOFFSET, cs.CARD_YOFFSET,
cs.SHADOW_XOFFSET, cs.SHADOW_YOFFSET) = \
(int(x) for x in lines_list[3].split())
except ValueError:
_perr(4, msg='invalid format')
return None
# lines_list[4]: default background
back = lines_list[4]
if not back:
_perr(5, msg='unexpected empty line')
return None
# lines_list[5]: all available backgrounds
cs.backnames = [f.strip() for f in lines_list[5].split(';')]
if back in cs.backnames:
cs.backindex = cs.backnames.index(back)
else:
cs.backnames.insert(0, back)
cs.backindex = 0
# if cs.type != 1: print cs.type, cs.name
return cs

View file

@ -498,19 +498,15 @@ def test(args=None):
fn = 'test.html'
if fn == '-':
f = sys.stdin
data = sys.stdin.read()
else:
try:
f = open(fn, 'r')
with open(fn, 'rt') as fh:
data = fh.read()
except IOError as msg:
print(fn, ":", msg)
sys.exit(1)
data = f.read()
if f is not sys.stdin:
f.close()
if silent:
f = formatter.NullFormatter()
else:

View file

@ -24,7 +24,7 @@
import os
from pysollib.mfxutil import Image, ImageTk, USE_PIL
from pysollib.mfxutil import Image, ImageTk, USE_PIL, print_err
from pysollib.pysoltk import copyImage, createBottom, createImage, loadImage
from pysollib.pysoltk import shadowImage
from pysollib.resource import CSI
@ -80,7 +80,7 @@ class Images:
# print '__loadCard:', filename
f = os.path.join(self.cs.dir, filename)
if not os.path.exists(f):
print('card image path %s does not exist' % (f))
print_err('card image path %s does not exist' % f)
return None
try:
img = loadImage(file=f)
@ -180,7 +180,12 @@ class Images:
for name in self.cs.backnames:
if name:
im = self.__loadCard(name)
self.__addBack(im, name)
if im:
self.__addBack(im, name)
else:
print_err('in {cs_dir}/config.txt: card back "{fname}" '
'does not exist'.format(
cs_dir=self.cs.dir, fname=name))
if progress:
progress.update(step=1)
# load bottoms

View file

@ -106,11 +106,6 @@ def init():
sys.exit("%s needs Tcl/Tk 8.4 or better (you have %s)" %
(pysollib.settings.TITLE, str(tkinter.TkVersion)))
pysollib.settings.WIN_SYSTEM = root.tk.call('tk', 'windowingsystem')
if pysollib.settings.WIN_SYSTEM == 'aqua':
# TkAqua displays the console automatically in application
# bundles, so we hide it here.
from pysollib.macosx.appSupport import hideTkConsole
hideTkConsole(root)
#
if pysollib.settings.USE_TILE == 'auto':
# check Tile

View file

@ -1,51 +0,0 @@
#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
# ---------------------------------------------------------------------------##
#
# Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
# Copyright (C) 2003 Mt. Hood Playing Card Co.
# Copyright (C) 2005-2009 Skomoroh
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ---------------------------------------------------------------------------##
"""
A number of function that enhance PySol on MacOSX when it used as a normal
GUI application (as opposed to an X11 application).
"""
import sys
from six.moves.tkinter import TclError
def runningAsOSXApp():
""" Returns True if-and-only-if running from the
PySol.app bundle on OSX """
return (sys.platform == 'darwin' and 'PySol.app' in sys.argv[0])
def hideTkConsole(root):
try:
root.tk.call('console', 'hide')
except TclError:
pass
def setupApp(app):
"""
Perform setup for the OSX application bundle.
"""
if not runningAsOSXApp():
return
hideTkConsole(app.top)

View file

@ -285,30 +285,23 @@ class KwStruct:
# ************************************************************************
def pickle(obj, filename, protocol=0):
f = None
try:
f = open(filename, "wb")
Pickler(f, protocol).dump(obj)
f.close()
f = None
with open(filename, "wb") as fh:
Pickler(fh, protocol).dump(obj)
# print "Pickled", filename
finally:
if f:
f.close()
pass
def unpickle(filename):
f, obj = None, None
obj = None
try:
f = open(filename, "rb")
x = Unpickler(f).load()
f.close()
f = None
with open(filename, "rb") as fh:
x = Unpickler(fh).load()
obj = x
# print "Unpickled", filename
finally:
if f:
f.close()
pass
return obj

View file

@ -524,9 +524,10 @@ class CardsetInfoDialog(MfxDialog):
frame.rowconfigure(1, weight=1)
#
text = ''
f = os.path.join(cardset.dir, "COPYRIGHT")
fn = os.path.join(cardset.dir, "COPYRIGHT")
try:
text = open(f).read()
with open(fn, "rt") as fh:
text = fh.read()
except Exception:
pass
if text:

View file

@ -487,9 +487,10 @@ class CardsetInfoDialog(MfxDialog):
frame.rowconfigure(1, weight=1)
#
text = ''
f = os.path.join(cardset.dir, "COPYRIGHT")
fn = os.path.join(cardset.dir, "COPYRIGHT")
try:
text = open(f).read()
with open(fn, "rt") as fh:
text = fh.read()
except Exception:
pass
if text:

View file

@ -295,7 +295,8 @@ class Base_HTMLViewer:
import codecs
return codecs.open(url, encoding='utf-8')
else:
return open(url, "rb")
with open(url, "rb") as fh:
return fh
return my_open(url), url
def display(self, url, add=1, relpath=1, xview=0, yview=0):

View file

@ -21,22 +21,11 @@
#
# ---------------------------------------------------------------------------##
from pysollib.macosx.appSupport import hideTkConsole
from pysollib.settings import TOOLKIT, USE_TILE
from pysollib.winsystems.common import BaseTkSettings, base_init_root_window
def init_root_window(root, app):
base_init_root_window(root, app)
if TOOLKIT == 'tk':
hideTkConsole(root)
if TOOLKIT == 'gtk':
pass
elif USE_TILE:
pass
else: # pure Tk
# root.option_add(...)
pass
class TkSettings(BaseTkSettings):

View file

@ -106,16 +106,10 @@ def base_init_root_window(root, app):
else:
root.wm_minsize(520, 360)
if TOOLKIT == 'gtk':
pass
if TOOLKIT == 'kivy':
pass
elif USE_TILE:
if TOOLKIT == 'tk' and USE_TILE:
theme = app.opt.tile_theme
init_tile(app, root)
set_theme(app, root, theme)
else:
pass
class BaseTkSettings:

View file

@ -1,13 +0,0 @@
rem simple script for building windows package
cd ..
rm -rf dist
mkdir dist
cp -r locale dist
cp -r freecell-solver dist
python setup.py py2exe
cp -r d:\Python\tcl\tile0.7.8 dist\tcl
cp -r data\music dist\data
python scripts\create_iss.py
"d:\Program Files\Inno Setup 5\ISCC.exe" setup.iss
pause

View file

@ -14,7 +14,7 @@ prog_name = 'PySol Fan Club edition'
dirs_list = []
files_list = []
for root, dirs, files in os.walk('dist'):
for root, dirs, files in os.walk(os.path.join('dist', 'pysol')):
if files:
files_list.append(root)
dirs_list.append(root)
@ -32,7 +32,7 @@ DefaultGroupName=%(prog_name)s
UninstallDisplayIcon={app}\\pysol.exe
Compression=lzma
SolidCompression=yes
SourceDir=dist
SourceDir=dist\\pysol
OutputDir=.
OutputBaseFilename=PySolFC_%(prog_version)s_setup
DisableWelcomePage=no
@ -47,16 +47,17 @@ Name: "{userdesktop}\\%(prog_name)s"; Filename: "{app}\\pysol.exe"
print('[Dirs]', file=out)
for d in dirs_list[1:]:
print('Name: "{app}%s"' % d.replace('dist', ''), file=out)
print('Name: "{app}%s"' % d.replace(os.path.join('dist', 'pysol'), ''),
file=out)
print(file=out)
print('[Files]', file=out)
print('Source: "*"; DestDir: "{app}"', file=out)
for d in files_list[1:]:
d = d.replace('dist\\', '')
d = d.replace(os.path.join('dist', 'pysol', ''), '')
print('Source: "%s\\*"; DestDir: "{app}\\%s"' % (d, d), file=out)
print('Source: "..\\vcredist_x86.exe"; DestDir: {tmp}; \
print('Source: "..\\..\\vcredist_x86.exe"; DestDir: {tmp}; \
Flags: deleteafterinstall', file=out)
print('[Run]\n\
Filename: {tmp}\\vcredist_x86.exe; \

View file

@ -44,6 +44,7 @@ print('ok 1 - imported')
for ver in PY_VERS:
for mod in [
'pysol_tests.acard_unit',
'pysol_tests.cardsetparser',
'pysol_tests.game_drag',
'pysol_tests.hint',
'pysol_tests.import_file1',

View file

@ -8,9 +8,6 @@ from pysollib.settings import VERSION
from setuptools import setup
if os.name == 'nt':
import py2exe # noqa: F401
def get_data_files(source, destination):
"""Iterates over all files under the given tree, to install them to the
@ -86,7 +83,6 @@ kw = {
'license': 'GPL',
'scripts': ['pysol.py'],
'packages': ['pysollib',
'pysollib.macosx',
'pysollib.winsystems',
'pysollib.tk',
'pysollib.tile',
@ -103,8 +99,6 @@ kw = {
}
if os.name == 'nt':
kw['windows'] = [{'script': 'pysol.py',
'icon_resources': [(1, 'data/pysol.ico')], }]
kw['packages'].remove('pysollib.pysolgtk')
setup(**kw)

View file

@ -56,7 +56,8 @@ DATA_FILES = ['docs', 'data', 'locale', 'scripts', 'COPYING', 'README.md',
] + SOLVER
RESOURCES = []
FRAMEWORKS = [SOLVER_LIB_PATH] if SOLVER_LIB_PATH else []
OPTIONS = dict(argv_emulation=True,
# with argv_emulation=True, the app window is not shown when launched
OPTIONS = dict(argv_emulation=False,
plist=PLIST,
iconfile=ICON_FILE,
resources=RESOURCES,

View file

@ -0,0 +1,62 @@
# Written by Juhani Numminen, under the MIT Expat License.
import unittest
from pysollib.cardsetparser import parse_cardset_config
from pysollib.resource import CSI, CardsetConfig
class MyTests(unittest.TestCase):
def _assertCcEqual(self, a, b, msg=None):
"""Assert that CardsetConfig objects a and b have equal attributes."""
return self.assertDictEqual(a.__dict__, b.__dict__, msg)
def test_good_cardset(self):
config_txt = """\
PySolFC solitaire cardset;4;.gif;1;52;7
123-dondorf;Dondorf
79 123 8
16 25 7 7
back01.gif
back01.gif
"""
reference = CardsetConfig()
reference.update(dict(
version=4,
ext='.gif',
type=CSI.TYPE_FRENCH,
ncards=52,
styles=[7],
ident='123-dondorf;Dondorf',
name='Dondorf',
CARDW=79,
CARDH=123,
CARDD=8,
CARD_XOFFSET=16,
CARD_YOFFSET=25,
SHADOW_XOFFSET=7,
SHADOW_YOFFSET=7,
backindex=0,
backnames=['back01.gif'],
))
self._assertCcEqual(
parse_cardset_config(config_txt.split('\n')),
reference,
'parse_cardset_config should parse well-formed v4 config.txt ' +
'correctly')
def test_reject_too_few_fields(self):
config_txt = """\
PySolFC solitaire cardset;4;.gif;1;52
123-dondorf;Dondorf
79 123 8
16 25 7 7
back01.gif
back01.gif
"""
self.assertIsNone(
parse_cardset_config(config_txt.split('\n')),
'parse_cardset_config should reject v4 config.txt with ' +
'a missing field on the first line')