pgn-clean-cg 0.0.0rc2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,132 @@
1
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
2
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
3
+
4
+ Contributing to pgn-clean-cg
5
+ ============================
6
+
7
+ First of all, thank you for considering contributing to pgn-clean-cg.
8
+
9
+ Before you open a pull request, please make sure that the code is correctly
10
+ formatted, and you have not introduced any new linter errors.
11
+
12
+ By submitting a pull request you certify that:
13
+
14
+ * You are the author of the contribution, or have the legal right to submit it.
15
+ * You either hold the copyright to the changes, or have the explicit legal
16
+ authorization to contribute them under this projects license.
17
+ * You understand the code.
18
+ * You accept full responsibility for it.
19
+
20
+ Requirements
21
+ ------------
22
+
23
+ In order to checkout the code and initialize the development environment you will need:
24
+
25
+ * Git
26
+ * Python 3
27
+ * Pip
28
+ * Automake
29
+
30
+ These packages can be installed using your favourite package manager on Linux.
31
+
32
+ Getting the code
33
+ ----------------
34
+
35
+ This project is using Git, and is hosted on `Codeberg`_.
36
+
37
+ .. code-block::
38
+
39
+ git clone ssh://git@codeberg.org/ehustad/pgn-cg-clean.git
40
+ cd pgn-clean-cg
41
+
42
+ Initializing the development environment
43
+ ----------------------------------------
44
+
45
+ The development environment can be initialized by using the make target "init"
46
+ from the top level source directory. This will create a virtual environment using
47
+ the Python venv module in .venv, install development tools, and install
48
+ pgn-cg-clean in `editable mode`_.
49
+
50
+ .. code-block::
51
+
52
+ make init
53
+
54
+ The make targets "env", "install-dev-tools", and "install" can be used if you
55
+ want to do this in stages. Note that "install" depends on "install-dev-tools"
56
+ and both "install" and "install-dev-tools" depends on "env".
57
+
58
+ To initialize the virtual environment, run the make target "env" from the top level
59
+ source directory:
60
+
61
+ .. code-block::
62
+
63
+ make env
64
+
65
+ To install development tools, such as black, mypy, pylint, run the make target
66
+ "install-dev-tools". Note that this requires the virtual environment in .venv
67
+ to exist, as all packages will be installed to that virtual environment:
68
+
69
+ .. code-block::
70
+
71
+ make install-dev-tools
72
+
73
+ To install pgn-cg-clean in editable mode, run the make target "install" from the
74
+ top level source directory:
75
+
76
+ .. code-block::
77
+
78
+ make install
79
+
80
+ Formatting code
81
+ ---------------
82
+
83
+ The code can formatted by using the make target "format" from the top level
84
+ source directory:
85
+
86
+ .. code-block::
87
+
88
+ make format
89
+
90
+ Running linters
91
+ ---------------
92
+
93
+ The linters can be run using make the make target "lint" from the top level
94
+ source directory:
95
+
96
+ .. code-block::
97
+
98
+ make lint
99
+
100
+ Running unit tests
101
+ ------------------
102
+
103
+ The unit tests can be run using the make target "test" from the top level
104
+ source directory:
105
+
106
+ .. code-block::
107
+
108
+ make test
109
+
110
+ Other make targets
111
+ ------------------
112
+
113
+ Please run the make target "help" from the top level source directory, or see
114
+ Makefile.
115
+
116
+ .. code-block::
117
+
118
+ make help
119
+
120
+ Creating a pull request
121
+ -----------------------
122
+
123
+ Please see the `Codeberg documentation`_.
124
+
125
+ Thanks
126
+ ------
127
+
128
+ Parts of this was based on the AI policy of the pip project.
129
+
130
+ .. _Codeberg: https://codeberg.org/ehustad/pgn-cg-clean/
131
+ .. _Codeberg documentation: https://docs.codeberg.org/collaborating/pull-requests-and-git-flow/
132
+ .. _editable mode: https://setuptools.pypa.io/en/latest/userguide/development_mode.html
@@ -0,0 +1,18 @@
1
+ MIT License
2
+
3
+ Copyright (c) <year> <copyright holders>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6
+ associated documentation files (the "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
9
+ following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial
12
+ portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15
+ LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
16
+ EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
18
+ USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ include tests/*.pgn
2
+ include tests/*.pgn.license
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgn-clean-cg
3
+ Version: 0.0.0rc2
4
+ Summary: Clean comments and Lichess computer analysis from pgn files
5
+ Author-email: Espen Sandøy Hustad <espen@ehustad.com>
6
+ License-Expression: MIT
7
+ Description-Content-Type: text/x-rst
8
+ License-File: LICENSE
9
+ Requires-Dist: chess
10
+ Dynamic: license-file
11
+
12
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
13
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
14
+
15
+ pgn-clean-cg - A command line utility for removing Lichess computer analysis from pgn files
16
+ ===========================================================================================
17
+
18
+ Are you tired of the computer spoiling all the fun before you even start to analyse your
19
+ most recent chess game? Look no further, pgn-clean-cg is a command line utility for cleaning
20
+ up pgn (Portable Game Notation) files.
21
+
22
+ * Remove per move computer evaluation.
23
+ * Remove per move comments, excluding clock times.
24
+ * Remove variations, excluding the main variation.
25
+ * Remove NAGs (Numeric Annotation Glyphs) such as ?, ??, !!, etc.
26
+
27
+ Usage
28
+ -----
29
+
30
+ Run the command "pgn-clean-cg" on one or more .pgn (Portable Game Notation) and specify destination .pgn file.
31
+ Example:
32
+
33
+ .. code-block::
34
+
35
+ pgn-clean-cg input1.pgn input2.pgn out.pgn
36
+
37
+ More verbose output can be added using the "-v" flag
38
+
39
+ .. code-block::
40
+
41
+ pgn-clean-cg -v input1.pgn input2.pgn out.pgn
42
+
43
+ The builtin help can be accessed using the "-h" flag
44
+
45
+ .. code-block::
46
+
47
+ pgn-clean-cg -h
48
+
49
+ Installation
50
+ ------------
51
+
52
+ The following command install pgn-clean-cg from the `Python Package Index`_. You will need
53
+ a working installation of Python3 and pip.
54
+
55
+ .. code-block::
56
+
57
+ pip install --upgrade pgn-clean-cg
58
+
59
+ Feedback and Contributing
60
+ -------------------------
61
+ Need help, or found a bug? Feel free to open an `issue`_ over on `Codeberg`_.
62
+
63
+ If you want to get involved, please read `CONTRIBUTING.rst`_.
64
+
65
+ .. _CONTRIBUTING.rst: https://codeberg.org/ehustad/pgn-cg-clean/src/branch/main/CONTRIBUTING.rst
66
+ .. _issue: https://codeberg.org/ehustad/pgn-cg-clean/issues
67
+ .. _Python Package Index: https://pypi.org/project/pgn-cg-clean/
68
+
69
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
70
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
71
+
72
+ Contributing to pgn-clean-cg
73
+ ============================
74
+
75
+ First of all, thank you for considering contributing to pgn-clean-cg.
76
+
77
+ Before you open a pull request, please make sure that the code is correctly
78
+ formatted, and you have not introduced any new linter errors.
79
+
80
+ By submitting a pull request you certify that:
81
+
82
+ * You are the author of the contribution, or have the legal right to submit it.
83
+ * You either hold the copyright to the changes, or have the explicit legal
84
+ authorization to contribute them under this projects license.
85
+ * You understand the code.
86
+ * You accept full responsibility for it.
87
+
88
+ Requirements
89
+ ------------
90
+
91
+ In order to checkout the code and initialize the development environment you will need:
92
+
93
+ * Git
94
+ * Python 3
95
+ * Pip
96
+ * Automake
97
+
98
+ These packages can be installed using your favourite package manager on Linux.
99
+
100
+ Getting the code
101
+ ----------------
102
+
103
+ This project is using Git, and is hosted on `Codeberg`_.
104
+
105
+ .. code-block::
106
+
107
+ git clone ssh://git@codeberg.org/ehustad/pgn-cg-clean.git
108
+ cd pgn-clean-cg
109
+
110
+ Initializing the development environment
111
+ ----------------------------------------
112
+
113
+ The development environment can be initialized by using the make target "init"
114
+ from the top level source directory. This will create a virtual environment using
115
+ the Python venv module in .venv, install development tools, and install
116
+ pgn-cg-clean in `editable mode`_.
117
+
118
+ .. code-block::
119
+
120
+ make init
121
+
122
+ The make targets "env", "install-dev-tools", and "install" can be used if you
123
+ want to do this in stages. Note that "install" depends on "install-dev-tools"
124
+ and both "install" and "install-dev-tools" depends on "env".
125
+
126
+ To initialize the virtual environment, run the make target "env" from the top level
127
+ source directory:
128
+
129
+ .. code-block::
130
+
131
+ make env
132
+
133
+ To install development tools, such as black, mypy, pylint, run the make target
134
+ "install-dev-tools". Note that this requires the virtual environment in .venv
135
+ to exist, as all packages will be installed to that virtual environment:
136
+
137
+ .. code-block::
138
+
139
+ make install-dev-tools
140
+
141
+ To install pgn-cg-clean in editable mode, run the make target "install" from the
142
+ top level source directory:
143
+
144
+ .. code-block::
145
+
146
+ make install
147
+
148
+ Formatting code
149
+ ---------------
150
+
151
+ The code can formatted by using the make target "format" from the top level
152
+ source directory:
153
+
154
+ .. code-block::
155
+
156
+ make format
157
+
158
+ Running linters
159
+ ---------------
160
+
161
+ The linters can be run using make the make target "lint" from the top level
162
+ source directory:
163
+
164
+ .. code-block::
165
+
166
+ make lint
167
+
168
+ Running unit tests
169
+ ------------------
170
+
171
+ The unit tests can be run using the make target "test" from the top level
172
+ source directory:
173
+
174
+ .. code-block::
175
+
176
+ make test
177
+
178
+ Other make targets
179
+ ------------------
180
+
181
+ Please run the make target "help" from the top level source directory, or see
182
+ Makefile.
183
+
184
+ .. code-block::
185
+
186
+ make help
187
+
188
+ Creating a pull request
189
+ -----------------------
190
+
191
+ Please see the `Codeberg documentation`_.
192
+
193
+ Thanks
194
+ ------
195
+
196
+ Parts of this was based on the AI policy of the pip project.
197
+
198
+ .. _Codeberg: https://codeberg.org/ehustad/pgn-cg-clean/
199
+ .. _Codeberg documentation: https://docs.codeberg.org/collaborating/pull-requests-and-git-flow/
200
+ .. _editable mode: https://setuptools.pypa.io/en/latest/userguide/development_mode.html
@@ -0,0 +1,56 @@
1
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
2
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
3
+
4
+ pgn-clean-cg - A command line utility for removing Lichess computer analysis from pgn files
5
+ ===========================================================================================
6
+
7
+ Are you tired of the computer spoiling all the fun before you even start to analyse your
8
+ most recent chess game? Look no further, pgn-clean-cg is a command line utility for cleaning
9
+ up pgn (Portable Game Notation) files.
10
+
11
+ * Remove per move computer evaluation.
12
+ * Remove per move comments, excluding clock times.
13
+ * Remove variations, excluding the main variation.
14
+ * Remove NAGs (Numeric Annotation Glyphs) such as ?, ??, !!, etc.
15
+
16
+ Usage
17
+ -----
18
+
19
+ Run the command "pgn-clean-cg" on one or more .pgn (Portable Game Notation) and specify destination .pgn file.
20
+ Example:
21
+
22
+ .. code-block::
23
+
24
+ pgn-clean-cg input1.pgn input2.pgn out.pgn
25
+
26
+ More verbose output can be added using the "-v" flag
27
+
28
+ .. code-block::
29
+
30
+ pgn-clean-cg -v input1.pgn input2.pgn out.pgn
31
+
32
+ The builtin help can be accessed using the "-h" flag
33
+
34
+ .. code-block::
35
+
36
+ pgn-clean-cg -h
37
+
38
+ Installation
39
+ ------------
40
+
41
+ The following command install pgn-clean-cg from the `Python Package Index`_. You will need
42
+ a working installation of Python3 and pip.
43
+
44
+ .. code-block::
45
+
46
+ pip install --upgrade pgn-clean-cg
47
+
48
+ Feedback and Contributing
49
+ -------------------------
50
+ Need help, or found a bug? Feel free to open an `issue`_ over on `Codeberg`_.
51
+
52
+ If you want to get involved, please read `CONTRIBUTING.rst`_.
53
+
54
+ .. _CONTRIBUTING.rst: https://codeberg.org/ehustad/pgn-cg-clean/src/branch/main/CONTRIBUTING.rst
55
+ .. _issue: https://codeberg.org/ehustad/pgn-cg-clean/issues
56
+ .. _Python Package Index: https://pypi.org/project/pgn-cg-clean/
@@ -0,0 +1,4 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
3
+
4
+ __version__ = "0.0.0rc2"
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
3
+
4
+ import sys
5
+
6
+ from . import cli
7
+
8
+ if __name__ == "__main__":
9
+ sys.exit(cli.main())
@@ -0,0 +1,100 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
3
+
4
+ import argparse
5
+ import sys
6
+
7
+ from pathlib import Path
8
+
9
+ from . import pgnutils
10
+
11
+
12
+ class VerboseVisitor(pgnutils.BaseVisitor):
13
+ def begin_game(self, gameinfo: pgnutils.GameInfo):
14
+ print(
15
+ f"\tCleaning game: {gameinfo.date} - {gameinfo.players} - {gameinfo.result}"
16
+ f" in {gameinfo.opening}"
17
+ )
18
+
19
+
20
+ def inputfile(filename: str) -> Path:
21
+ p = Path(filename)
22
+
23
+ if not p.is_file():
24
+ raise argparse.ArgumentTypeError(f"The file '{p}' does not exist.")
25
+
26
+ return p
27
+
28
+
29
+ def outputfile(filename: str) -> Path:
30
+ p = Path(filename)
31
+
32
+ if p.is_dir():
33
+ raise argparse.ArgumentTypeError(f"'{p}' is a directory.")
34
+ return p
35
+
36
+
37
+ def main() -> int:
38
+ parser = argparse.ArgumentParser(
39
+ prog="pgn-clean-cg",
40
+ description="Clean pgn files for comments, variations, and Lichess computer analysis.",
41
+ )
42
+
43
+ parser.add_argument(
44
+ "-v", "--verbose", action="store_true", help="Increase verbosity"
45
+ )
46
+
47
+ parser.add_argument(
48
+ "input",
49
+ type=inputfile,
50
+ metavar="INPUT_FILES",
51
+ nargs="+",
52
+ help="One or more input .pgn file(s)",
53
+ )
54
+ parser.add_argument(
55
+ "output", type=outputfile, metavar="OUTPUT_FILE", help="Output .pgn file"
56
+ )
57
+
58
+ args = parser.parse_args()
59
+
60
+ if args.output.exists():
61
+ overwrite = str(
62
+ input(
63
+ f"The file {args.output} already exists. Do you want to overwrite (y/N)?"
64
+ )
65
+ ).lower()
66
+ if overwrite != "y":
67
+ return 1
68
+
69
+ fixed_games = []
70
+ cg_cleaner = pgnutils.CGCleaner()
71
+
72
+ if args.verbose:
73
+ cg_cleaner.register_visitor(VerboseVisitor())
74
+
75
+ for file in args.input:
76
+ try:
77
+ with file.open() as f:
78
+ print(f"Cleaning file: '{file}'")
79
+ fixed_games.extend(cg_cleaner.clean(f))
80
+ except (OSError, PermissionError) as e:
81
+ skip = str(
82
+ input(f"Failed to open file: {e}. Do you want to skip file (Y/n)?")
83
+ ).lower()
84
+ if skip != "y":
85
+ return 1
86
+
87
+ try:
88
+ with args.output.open("w") as f:
89
+ for game in fixed_games:
90
+ print(game, file=f, end="\n\n")
91
+
92
+ except (OSError, PermissionError) as e:
93
+ print(f"Aborting: Failed to open file for writing: {e}.", file=sys.stderr)
94
+ return 1
95
+
96
+ return 0
97
+
98
+
99
+ if __name__ == "__main__":
100
+ sys.exit(main())
@@ -0,0 +1,125 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
3
+
4
+ from dataclasses import dataclass
5
+ from typing import List, TextIO
6
+
7
+ import chess.pgn
8
+
9
+
10
+ def _extract_item_from_list(l: chess.pgn.Headers, item: str, default_value: str) -> str:
11
+ try:
12
+ return l[item]
13
+ except KeyError:
14
+ return default_value
15
+
16
+
17
+ class CGCleaner:
18
+ def clean(self, pgn: TextIO) -> List[chess.pgn.Game]:
19
+ ret = []
20
+
21
+ while True:
22
+ game = chess.pgn.read_game(pgn)
23
+ if game is None:
24
+ break
25
+
26
+ ret.append(self._clean_game(game))
27
+
28
+ return ret
29
+
30
+ def register_visitor(self, visitor: BaseVisitor):
31
+ self.visitor = visitor
32
+
33
+ def _clean_game(self, game: chess.pgn.Game) -> chess.pgn.Game:
34
+ gameinfo = self._build_gameinfo(game)
35
+ self.visitor.begin_game(gameinfo)
36
+
37
+ for move in game.mainline():
38
+ move.nags = set()
39
+ clock = move.clock()
40
+ move.comment = ""
41
+ move.set_clock(clock)
42
+ self._clean_variations(move)
43
+
44
+ self.visitor.end_game(gameinfo)
45
+
46
+ return game
47
+
48
+ def _build_gameinfo(self, game: chess.pgn.Game) -> GameInfo:
49
+ white = Player(
50
+ _extract_item_from_list(game.headers, "White", "N.N"),
51
+ _extract_item_from_list(game.headers, "WhiteElo", ""),
52
+ )
53
+
54
+ black = Player(
55
+ _extract_item_from_list(game.headers, "Black", "N.N"),
56
+ _extract_item_from_list(game.headers, "BlackElo", ""),
57
+ )
58
+
59
+ opening = Opening(
60
+ _extract_item_from_list(game.headers, "ECO", ""),
61
+ _extract_item_from_list(game.headers, "Opening", "Unknown opening"),
62
+ )
63
+
64
+ return GameInfo(
65
+ Players(white, black),
66
+ _extract_item_from_list(game.headers, "Date", "unknown date"),
67
+ _extract_item_from_list(game.headers, "Result", "unknown result"),
68
+ opening,
69
+ )
70
+
71
+ def _clean_variations(self, move: chess.pgn.ChildNode):
72
+ if move.variations:
73
+ move.variations = move.variations[:1]
74
+
75
+ def __init__(self):
76
+ self.visitor = BaseVisitor()
77
+
78
+
79
+ @dataclass
80
+ class Player:
81
+ name: str
82
+ elo: str
83
+
84
+ def __repr__(self):
85
+ if self.elo:
86
+ return f"{self.name} ({self.elo})"
87
+
88
+ return self.name
89
+
90
+
91
+ @dataclass
92
+ class Players:
93
+ white: Player
94
+ black: Player
95
+
96
+ def __repr__(self):
97
+ return f"{self.white} vs {self.black}"
98
+
99
+
100
+ @dataclass
101
+ class Opening:
102
+ eco: str
103
+ name: str
104
+
105
+ def __repr__(self):
106
+ if self.eco:
107
+ return f"{self.eco}:{self.name}"
108
+
109
+ return self.name
110
+
111
+
112
+ @dataclass
113
+ class GameInfo:
114
+ players: Players
115
+ date: str
116
+ result: str
117
+ opening: Opening
118
+
119
+
120
+ class BaseVisitor:
121
+ def begin_game(self, gameinfo: GameInfo):
122
+ pass
123
+
124
+ def end_game(self, gameinfo: GameInfo):
125
+ pass
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: pgn-clean-cg
3
+ Version: 0.0.0rc2
4
+ Summary: Clean comments and Lichess computer analysis from pgn files
5
+ Author-email: Espen Sandøy Hustad <espen@ehustad.com>
6
+ License-Expression: MIT
7
+ Description-Content-Type: text/x-rst
8
+ License-File: LICENSE
9
+ Requires-Dist: chess
10
+ Dynamic: license-file
11
+
12
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
13
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
14
+
15
+ pgn-clean-cg - A command line utility for removing Lichess computer analysis from pgn files
16
+ ===========================================================================================
17
+
18
+ Are you tired of the computer spoiling all the fun before you even start to analyse your
19
+ most recent chess game? Look no further, pgn-clean-cg is a command line utility for cleaning
20
+ up pgn (Portable Game Notation) files.
21
+
22
+ * Remove per move computer evaluation.
23
+ * Remove per move comments, excluding clock times.
24
+ * Remove variations, excluding the main variation.
25
+ * Remove NAGs (Numeric Annotation Glyphs) such as ?, ??, !!, etc.
26
+
27
+ Usage
28
+ -----
29
+
30
+ Run the command "pgn-clean-cg" on one or more .pgn (Portable Game Notation) and specify destination .pgn file.
31
+ Example:
32
+
33
+ .. code-block::
34
+
35
+ pgn-clean-cg input1.pgn input2.pgn out.pgn
36
+
37
+ More verbose output can be added using the "-v" flag
38
+
39
+ .. code-block::
40
+
41
+ pgn-clean-cg -v input1.pgn input2.pgn out.pgn
42
+
43
+ The builtin help can be accessed using the "-h" flag
44
+
45
+ .. code-block::
46
+
47
+ pgn-clean-cg -h
48
+
49
+ Installation
50
+ ------------
51
+
52
+ The following command install pgn-clean-cg from the `Python Package Index`_. You will need
53
+ a working installation of Python3 and pip.
54
+
55
+ .. code-block::
56
+
57
+ pip install --upgrade pgn-clean-cg
58
+
59
+ Feedback and Contributing
60
+ -------------------------
61
+ Need help, or found a bug? Feel free to open an `issue`_ over on `Codeberg`_.
62
+
63
+ If you want to get involved, please read `CONTRIBUTING.rst`_.
64
+
65
+ .. _CONTRIBUTING.rst: https://codeberg.org/ehustad/pgn-cg-clean/src/branch/main/CONTRIBUTING.rst
66
+ .. _issue: https://codeberg.org/ehustad/pgn-cg-clean/issues
67
+ .. _Python Package Index: https://pypi.org/project/pgn-cg-clean/
68
+
69
+ .. SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
70
+ .. SPDX-License-Identifier: CC-BY-SA-4.0
71
+
72
+ Contributing to pgn-clean-cg
73
+ ============================
74
+
75
+ First of all, thank you for considering contributing to pgn-clean-cg.
76
+
77
+ Before you open a pull request, please make sure that the code is correctly
78
+ formatted, and you have not introduced any new linter errors.
79
+
80
+ By submitting a pull request you certify that:
81
+
82
+ * You are the author of the contribution, or have the legal right to submit it.
83
+ * You either hold the copyright to the changes, or have the explicit legal
84
+ authorization to contribute them under this projects license.
85
+ * You understand the code.
86
+ * You accept full responsibility for it.
87
+
88
+ Requirements
89
+ ------------
90
+
91
+ In order to checkout the code and initialize the development environment you will need:
92
+
93
+ * Git
94
+ * Python 3
95
+ * Pip
96
+ * Automake
97
+
98
+ These packages can be installed using your favourite package manager on Linux.
99
+
100
+ Getting the code
101
+ ----------------
102
+
103
+ This project is using Git, and is hosted on `Codeberg`_.
104
+
105
+ .. code-block::
106
+
107
+ git clone ssh://git@codeberg.org/ehustad/pgn-cg-clean.git
108
+ cd pgn-clean-cg
109
+
110
+ Initializing the development environment
111
+ ----------------------------------------
112
+
113
+ The development environment can be initialized by using the make target "init"
114
+ from the top level source directory. This will create a virtual environment using
115
+ the Python venv module in .venv, install development tools, and install
116
+ pgn-cg-clean in `editable mode`_.
117
+
118
+ .. code-block::
119
+
120
+ make init
121
+
122
+ The make targets "env", "install-dev-tools", and "install" can be used if you
123
+ want to do this in stages. Note that "install" depends on "install-dev-tools"
124
+ and both "install" and "install-dev-tools" depends on "env".
125
+
126
+ To initialize the virtual environment, run the make target "env" from the top level
127
+ source directory:
128
+
129
+ .. code-block::
130
+
131
+ make env
132
+
133
+ To install development tools, such as black, mypy, pylint, run the make target
134
+ "install-dev-tools". Note that this requires the virtual environment in .venv
135
+ to exist, as all packages will be installed to that virtual environment:
136
+
137
+ .. code-block::
138
+
139
+ make install-dev-tools
140
+
141
+ To install pgn-cg-clean in editable mode, run the make target "install" from the
142
+ top level source directory:
143
+
144
+ .. code-block::
145
+
146
+ make install
147
+
148
+ Formatting code
149
+ ---------------
150
+
151
+ The code can formatted by using the make target "format" from the top level
152
+ source directory:
153
+
154
+ .. code-block::
155
+
156
+ make format
157
+
158
+ Running linters
159
+ ---------------
160
+
161
+ The linters can be run using make the make target "lint" from the top level
162
+ source directory:
163
+
164
+ .. code-block::
165
+
166
+ make lint
167
+
168
+ Running unit tests
169
+ ------------------
170
+
171
+ The unit tests can be run using the make target "test" from the top level
172
+ source directory:
173
+
174
+ .. code-block::
175
+
176
+ make test
177
+
178
+ Other make targets
179
+ ------------------
180
+
181
+ Please run the make target "help" from the top level source directory, or see
182
+ Makefile.
183
+
184
+ .. code-block::
185
+
186
+ make help
187
+
188
+ Creating a pull request
189
+ -----------------------
190
+
191
+ Please see the `Codeberg documentation`_.
192
+
193
+ Thanks
194
+ ------
195
+
196
+ Parts of this was based on the AI policy of the pip project.
197
+
198
+ .. _Codeberg: https://codeberg.org/ehustad/pgn-cg-clean/
199
+ .. _Codeberg documentation: https://docs.codeberg.org/collaborating/pull-requests-and-git-flow/
200
+ .. _editable mode: https://setuptools.pypa.io/en/latest/userguide/development_mode.html
@@ -0,0 +1,24 @@
1
+ CONTRIBUTING.rst
2
+ LICENSE
3
+ MANIFEST.in
4
+ README.rst
5
+ pyproject.toml
6
+ pgn_clean_cg/__init__.py
7
+ pgn_clean_cg/__main__.py
8
+ pgn_clean_cg/cli.py
9
+ pgn_clean_cg/pgnutils.py
10
+ pgn_clean_cg.egg-info/PKG-INFO
11
+ pgn_clean_cg.egg-info/SOURCES.txt
12
+ pgn_clean_cg.egg-info/dependency_links.txt
13
+ pgn_clean_cg.egg-info/entry_points.txt
14
+ pgn_clean_cg.egg-info/requires.txt
15
+ pgn_clean_cg.egg-info/top_level.txt
16
+ tests/expected.pgn
17
+ tests/expected.pgn.license
18
+ tests/source.pgn
19
+ tests/source.pgn.license
20
+ tests/source_with_clk.pgn
21
+ tests/source_with_clk.pgn.license
22
+ tests/source_with_computer_eval.pgn
23
+ tests/source_with_computer_eval.pgn.license
24
+ tests/test_pgnutils.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pgn-clean-cg = pgn_clean_cg.cli:main
@@ -0,0 +1 @@
1
+ pgn_clean_cg
@@ -0,0 +1,43 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
3
+
4
+ [build-system]
5
+ requires = ["setuptools"]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "pgn-clean-cg"
10
+ dynamic = [
11
+ "version",
12
+ "readme",
13
+ ]
14
+
15
+ authors = [
16
+ {name = "Espen Sandøy Hustad", email = "espen@ehustad.com"},
17
+ ]
18
+ description = "Clean comments and Lichess computer analysis from pgn files"
19
+ license = "MIT"
20
+
21
+ dependencies = [
22
+ "chess",
23
+ ]
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "black",
28
+ "mypy",
29
+ "pylint",
30
+ "reuse",
31
+ ]
32
+
33
+ [project.scripts]
34
+ pgn-clean-cg = "pgn_clean_cg.cli:main"
35
+
36
+ [tool.setuptools]
37
+ packages = [
38
+ "pgn_clean_cg"
39
+ ]
40
+
41
+ [tool.setuptools.dynamic]
42
+ version = {attr = "pgn_clean_cg.__version__"}
43
+ readme = {file = ["README.rst", "CONTRIBUTING.rst"] }
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,23 @@
1
+ [Event "rated bullet game"]
2
+ [Site "https://lichess.org/q3p2A91e"]
3
+ [Date "2026.07.13"]
4
+ [Round "-"]
5
+ [White "tsunami10"]
6
+ [Black "Secret_Magnus"]
7
+ [Result "0-1"]
8
+ [GameId "q3p2A91e"]
9
+ [UTCDate "2026.07.13"]
10
+ [UTCTime "13:34:00"]
11
+ [WhiteElo "2964"]
12
+ [BlackElo "3149"]
13
+ [WhiteRatingDiff "-3"]
14
+ [BlackRatingDiff "+3"]
15
+ [BlackTitle "IM"]
16
+ [Variant "Standard"]
17
+ [TimeControl "60+0"]
18
+ [ECO "B08"]
19
+ [Opening "Pirc Defense: Classical Variation"]
20
+ [Termination "Normal"]
21
+ [Annotator "lichess.org"]
22
+
23
+ 1. Nf3 d6 2. d4 Nf6 3. Nc3 g6 4. e4 Bg7 5. e5 dxe5 6. dxe5 Qxd1+ 7. Nxd1 Ng4 8. Bf4 Nc6 9. Bb5 Bd7 10. Bxc6 Bxc6 11. e6 fxe6 12. Ne3 Nxe3 13. fxe3 Bxb2 14. Rb1 Bc3+ 15. Ke2 O-O-O 16. Ng1 Bxg2
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
3
+
@@ -0,0 +1,23 @@
1
+ [Event "rated bullet game"]
2
+ [Site "https://lichess.org/q3p2A91e"]
3
+ [Date "2026.07.13"]
4
+ [Round "-"]
5
+ [White "tsunami10"]
6
+ [Black "Secret_Magnus"]
7
+ [Result "0-1"]
8
+ [GameId "q3p2A91e"]
9
+ [UTCDate "2026.07.13"]
10
+ [UTCTime "13:34:00"]
11
+ [WhiteElo "2964"]
12
+ [BlackElo "3149"]
13
+ [WhiteRatingDiff "-3"]
14
+ [BlackRatingDiff "+3"]
15
+ [BlackTitle "IM"]
16
+ [Variant "Standard"]
17
+ [TimeControl "60+0"]
18
+ [ECO "B08"]
19
+ [Opening "Pirc Defense: Classical Variation"]
20
+ [Termination "Normal"]
21
+ [Annotator "lichess.org"]
22
+
23
+ 1. Nf3 d6 2. d4 Nf6 3. Nc3 g6 4. e4 Bg7 5. e5 dxe5 6. dxe5 Qxd1+ 7. Nxd1 Ng4 8. Bf4 Nc6 9. Bb5 Bd7 (9... O-O 10. O-O (10. b3 h5) 10... Nd4) 10. Bxc6 Bxc6 11. e6 fxe6 12. Ne3 Nxe3 13. fxe3 Bxb2 (13... h5 14. Nd4 Bd7 (14... Rd8)) 14. Rb1 Bc3+ 15. Ke2 O-O-O 16. Ng1 Bxg2
@@ -0,0 +1,2 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
@@ -0,0 +1,25 @@
1
+ [Event "Round 1: Perreard, Nicolas - Dlugosz, Jan"]
2
+ [Site "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC/uPir5Hui"]
3
+ [Date "2026.07.13"]
4
+ [Round "1.7"]
5
+ [White "Perreard, Nicolas"]
6
+ [Black "Dlugosz, Jan"]
7
+ [Result "1-0"]
8
+ [WhiteElo "2041"]
9
+ [WhiteFideId "1330861"]
10
+ [BlackElo "1600"]
11
+ [BlackFideId "545027633"]
12
+ [Variant "Chess960"]
13
+ [ECO "?"]
14
+ [Opening "?"]
15
+ [FEN "bbqrnnkr/pppppppp/8/8/8/8/PPPPPPPP/BBQRNNKR w KQkq - 0 1"]
16
+ [SetUp "1"]
17
+ [UTCDate "2026.07.13"]
18
+ [UTCTime "07:57:24"]
19
+ [BroadcastName "59th Biel International Chess Festival 2026 | Open | Free Style 960 (FSC)"]
20
+ [BroadcastURL "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC"]
21
+ [GameURL "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC/uPir5Hui"]
22
+
23
+ 1. d4 { [%eval 0.24] [%clk 0:58:15] } 1... d5 { [%eval 0.19] [%clk 0:59:12] } 2. b3 { [%eval 0.23] [%clk 0:57:33] } 2... Nf6?! { [%eval 0.87] } { Inaccuracy. c5 was best. } { [%clk 0:58:38] } 3. c4 { [%eval 0.74] [%clk 0:56:51] } 3... c6 { [%eval 0.9] [%clk 0:58:27] } 4. Nf3 { [%eval 0.77] [%clk 0:51:29] } 4... N8d7?! { [%eval 1.43] } { Inaccuracy. b6 was best. } { [%clk 0:56:42] } 5. Ne3 { [%eval 1.06] [%clk 0:50:22] } 5... e6 { [%eval 0.95] [%clk 0:56:29] } 6. h4 { [%eval 0.99] [%clk 0:44:11] } 6... h5 { [%eval 0.9] [%clk 0:54:47] } 7. Qa3 { [%eval 0.58] [%clk 0:42:58] } 7... g6 { [%eval 1.03] [%clk 0:52:36] } 8. Ng5 { [%eval 0.71] [%clk 0:41:42] } 8... Nh7 { [%eval 1.15] [%clk 0:51:16] } 9. Nxe6?! { [%eval 0.05] } { Inaccuracy. Qc1 was best. } { [%clk 0:36:21] } 9... fxe6 { [%eval 0.14] [%clk 0:51:23] } 10. Bxg6? { [%eval -1.27] } { Mistake. cxd5 was best. } { [%clk 0:36:48] } 10... Nhf8?? { [%eval 2.53] } { Blunder. Ndf6 was best. } { [%clk 0:50:11] } 11. Bd3?? { [%eval -0.83] } { Blunder. Qe7 was best. } { [%clk 0:36:54] } 11... Nf6 { [%eval -0.75] [%clk 0:49:51] } 12. Rh3 { [%eval -1.09] [%clk 0:30:45] } 12... Kf7? { [%eval 0.04] } { Mistake. Qc7 was best. } { [%clk 0:49:06] } 13. Rf3 { [%eval 0.07] [%clk 0:30:37] } 13... Bd6? { [%eval 1.2] } { Mistake. Ng6 was best. } { [%clk 0:48:42] } 14. Qxa7?! { [%eval 0.22] } { Inaccuracy. Qc1 was best. } { [%clk 0:30:36] } 14... Ke7 { [%eval 0.76] [%clk 0:48:19] } 15. c5 { [%eval 0.74] [%clk 0:29:15] } 15... Bb8 { [%eval 1.14] [%clk 0:48:38] } 16. Qa3 { [%eval 1.11] [%clk 0:29:28] } 16... N8d7 { [%eval 1.09] [%clk 0:47:58] } 17. O-O-O?! { [%eval 0.0] } { Inaccuracy. g3 was best. } { [%clk 0:29:42] } 17... Bc7 { [%eval 0.0] [%clk 0:48:07] } 18. b4?! { [%eval -0.8] } { Inaccuracy. Kb1 was best. } { [%clk 0:27:36] } 1-0
24
+
25
+
@@ -0,0 +1,2 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
@@ -0,0 +1,26 @@
1
+ [Event "Round 1: Brixius, Dirk - Cherniaev, Alexander"]
2
+ [Site "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC/Yc5uWTEm"]
3
+ [Date "2026.07.13"]
4
+ [Round "1.2"]
5
+ [White "Brixius, Dirk"]
6
+ [Black "Cherniaev, Alexander"]
7
+ [Result "0-1"]
8
+ [WhiteElo "1821"]
9
+ [WhiteFideId "12909734"]
10
+ [BlackElo "2275"]
11
+ [BlackTitle "GM"]
12
+ [BlackFideId "4117301"]
13
+ [Variant "Chess960"]
14
+ [ECO "?"]
15
+ [Opening "?"]
16
+ [FEN "bbqrnnkr/pppppppp/8/8/8/8/PPPPPPPP/BBQRNNKR w KQkq - 0 1"]
17
+ [SetUp "1"]
18
+ [UTCDate "2026.07.13"]
19
+ [UTCTime "07:57:24"]
20
+ [BroadcastName "59th Biel International Chess Festival 2026 | Open | Free Style 960 (FSC)"]
21
+ [BroadcastURL "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC"]
22
+ [GameURL "https://lichess.org/broadcast/59th-biel-international-chess-festival-2026-open-free-style-960-fsc/round-1/hxv9N3yC/Yc5uWTEm"]
23
+
24
+ 1. c4 { [%eval 0.35] [%clk 1:00:30] } 1... c5 { [%eval 0.15] [%clk 0:59:43] } 2. b3 { [%eval 0.11] [%clk 0:59:02] } 2... b6 { [%eval 0.23] [%clk 1:00:06] } 3. d4 { [%eval -0.06] [%clk 0:57:43] } 3... cxd4 { [%eval 0.21] [%clk 1:00:19] } 4. Bxd4 { [%eval 0.15] [%clk 0:57:21] } 4... Ne6 { [%eval 0.13] [%clk 1:00:31] } 5. e3?! { [%eval -0.68] } { Inaccuracy. Bb2 was best. } { [%clk 0:56:54] } 5... Nxd4 { [%eval -0.71] [%clk 1:00:44] } 6. exd4 { [%eval -0.71] [%clk 0:56:41] } 6... e6 { [%eval -0.69] [%clk 1:00:29] } 7. Qe3 { [%eval -0.99] [%clk 0:54:52] } 7... Nf6 { [%eval -1.04] [%clk 1:00:36] } 8. Nf3 { [%eval -0.96] [%clk 0:52:12] } 8... Qc7 { [%eval -0.73] [%clk 0:54:12] } 9. Ng3 { [%eval -1.03] [%clk 0:49:29] } 9... Qf4 { [%eval -0.75] [%clk 0:47:00] } 10. Ne2 { [%eval -0.87] [%clk 0:45:11] } 10... Qxe3 { [%eval -0.79] [%clk 0:42:56] } 11. fxe3 { [%eval -0.84] [%clk 0:45:38] } 11... O-O { [%eval -0.79] [%clk 0:43:12] } 12. Nc3 { [%eval -0.78] [%clk 0:42:47] } 12... Rc8 { [%eval -0.76] [%clk 0:32:31] } 13. e4 { [%eval -0.72] [%clk 0:40:55] } 13... d5 { [%eval -0.86] [%clk 0:25:26] } 14. e5 { [%eval -1.06] [%clk 0:37:20] } 14... Nd7?! { [%eval -0.33] } { Inaccuracy. Nh5 was best. } { [%clk 0:24:52] } 15. Bd3 { [%eval -0.22] [%clk 0:35:28] } 15... f6 { [%eval -0.4] [%clk 0:23:40] } 16. cxd5?! { [%eval -1.4] } { Inaccuracy. Nxd5 was best. } { [%clk 0:34:23] } 16... exd5? { [%eval 0.03] } { Mistake. Rxc3 was best. } { [%clk 0:24:05] } 17. e6?? { [%eval -1.69] } { Blunder. Bf5 was best. } { [%clk 0:34:20] } 17... Rxc3 { [%eval -1.75] [%clk 0:24:23] } 18. exd7 { [%eval -1.77] [%clk 0:34:35] } 18... Bc6 { [%eval -1.8] [%clk 0:17:37] } 19. Kf2 { [%eval -1.59] [%clk 0:34:00] } 19... Bxd7 { [%eval -1.66] [%clk 0:17:52] } 20. Rhe1 { [%eval -1.79] [%clk 0:32:27] } 20... Bd6 { [%eval -1.82] [%clk 0:18:03] } 21. g3 { [%eval -2.39] [%clk 0:27:46] } 21... Rfc8 { [%eval -2.33] [%clk 0:16:52] } 22. Kg2 { [%eval -2.4] [%clk 0:27:49] } 22... Bb4 { [%eval -2.39] [%clk 0:15:38] } 23. Re2 { [%eval -2.36] [%clk 0:25:34] } 23... Rc1 { [%eval -2.05] [%clk 0:15:39] } 24. Rxc1 { [%eval -1.96] [%clk 0:24:44] } 24... Rxc1 { [%eval -2.09] [%clk 0:16:07] } 25. Rc2 { [%eval -2.1] [%clk 0:20:02] } 25... Rd1? { [%eval -0.71] } { Mistake. Ra1 was best. } { [%clk 0:13:38] } 26. Ba6?? { [%eval -3.31] } { Blunder. Rc7 was best. } { [%clk 0:19:52] } 26... Bf5 { [%eval -3.26] [%clk 0:13:50] } 27. Rc7 { [%eval -3.19] [%clk 0:17:51] } 27... Be4 { [%eval -3.21] [%clk 0:14:15] } 28. Kf2 { [%eval -3.5] [%clk 0:17:54] } 28... Ra1 { [%eval -3.36] [%clk 0:14:38] } 29. a4 { [%eval -3.5] [%clk 0:17:14] } 29... Ra2+ { [%eval -3.16] [%clk 0:13:33] } 30. Ke3 { [%eval -3.65] [%clk 0:17:25] } 30... Rb2 { [%eval -3.94] [%clk 0:13:49] } 31. Rc8+ { [%eval -4.09] [%clk 0:15:04] } 31... Kf7 { [%eval -3.68] [%clk 0:13:54] } 32. Bc4?! { [%eval -4.65] } { Inaccuracy. Be2 was best. } { [%clk 0:13:35] } 32... Bxf3 { [%eval -4.54] [%clk 0:14:09] } 33. Kxf3 { [%eval -4.7] [%clk 0:13:55] } 33... dxc4 { [%eval -4.74] [%clk 0:14:31] } 34. bxc4 { [%eval -4.58] [%clk 0:14:13] } 34... Bc3 { [%eval -4.34] [%clk 0:10:54] } 35. Rc7+ { [%eval -4.48] [%clk 0:13:21] } 35... Ke6 { [%eval -4.09] [%clk 0:10:12] } 36. d5+ { [%eval -4.32] [%clk 0:13:21] } 36... Kd6 { [%eval -4.31] [%clk 0:10:36] } 37. Rxg7 { [%eval -4.22] [%clk 0:13:23] } 37... Rxh2 { [%eval -4.08] [%clk 0:10:07] } 38. Rxa7 { [%eval -4.1] [%clk 0:13:28] } 38... h5 { [%eval -3.83] [%clk 0:08:19] } 39. Ke4 { [%eval -4.65] [%clk 0:08:19] } 39... h4 { [%eval -4.52] [%clk 0:05:23] } 40. gxh4 { [%eval -4.82] [%clk 0:07:43] } 40... Rxh4+ { [%eval -4.89] [%clk 0:05:47] } 41. Kd3 { [%eval -5.42] [%clk 0:07:45] } 41... Be5 { [%eval -5.18] [%clk 0:05:54] } 42. a5 { [%eval -5.36] [%clk 0:07:30] } 42... Rd4+ { [%eval -5.27] [%clk 0:06:09] } 43. Ke3 { [%eval -5.63] [%clk 0:06:58] } 43... Rxc4 { [%eval -5.33] [%clk 0:06:32] } 44. axb6 { [%eval -5.02] [%clk 0:05:03] } 44... Kxd5 { [%eval -5.21] [%clk 0:06:34] } 45. Re7 { [%eval -6.13] [%clk 0:04:00] } 45... Rc3+ { [%eval -6.59] [%clk 0:06:47] } 46. Kd2 { [%eval -6.3] [%clk 0:04:08] } 46... Rb3 { [%eval -6.28] [%clk 0:07:11] } 47. b7 { [%eval -6.07] [%clk 0:04:22] } 47... Kc6 { [%eval -5.96] [%clk 0:07:32] } 0-1
25
+
26
+
@@ -0,0 +1,3 @@
1
+ # SPDX-FileCopyrightText: none
2
+ # SPDX-License-Identifier: CC0-1.0
3
+
@@ -0,0 +1,81 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # SPDX-FileCopyrightText: 2026 Espen Sandøy Hustad <espen@ehustad.com>
3
+
4
+ from pathlib import Path
5
+ from typing import List
6
+ import unittest
7
+
8
+ import chess.pgn
9
+
10
+ from pgn_clean_cg import pgnutils
11
+
12
+
13
+ def _get_path(filename: str) -> Path:
14
+ return Path(__file__).parent.joinpath(filename)
15
+
16
+
17
+ class TestPGNUtils(unittest.TestCase):
18
+
19
+ def test_remove_comment(self):
20
+ games = self._load_cleaned_games("source_with_computer_eval.pgn")
21
+ for game in games:
22
+ for move in game.mainline():
23
+ move.set_clock(None)
24
+ self.assertFalse(move.comment)
25
+
26
+ def test_remove_eval(self):
27
+ games = self._load_cleaned_games("source_with_computer_eval.pgn")
28
+ for game in games:
29
+ for move in game.mainline():
30
+ self.assertTrue(move.eval() is None)
31
+
32
+ def test_remove_nags(self):
33
+ games = self._load_cleaned_games("source_with_computer_eval.pgn")
34
+ for game in games:
35
+ for move in game.mainline():
36
+ self.assertFalse(move.nags)
37
+
38
+ def test_remove_variations(self):
39
+ actual = self._load_cleaned_games("source.pgn")
40
+ expected = self._load_raw_games("expected.pgn")
41
+
42
+ self.assertEqual(len(actual), len(expected))
43
+
44
+ for i in range(len(actual)):
45
+ self.assertEqual(str(actual[i]), str(expected[i]))
46
+
47
+ def test_retain_clock(self):
48
+ games = self._load_cleaned_games("source_with_clk.pgn")
49
+ for game in games:
50
+ for move in game.mainline():
51
+ self.assertTrue(move.clock())
52
+
53
+ def _load_raw_games(self, name: str) -> List[chess.pgn.Game]:
54
+ ret = []
55
+
56
+ with _get_path(name).open() as f:
57
+ while True:
58
+ game = chess.pgn.read_game(f)
59
+ if game is None:
60
+ break
61
+ ret.append(game)
62
+
63
+ self.assertTrue(ret)
64
+ return ret
65
+
66
+ def _load_cleaned_games(self, name: str) -> List[chess.pgn.Game]:
67
+ ret = []
68
+
69
+ with _get_path(name).open() as f:
70
+ ret = self.cgcleaner.clean(f)
71
+
72
+ self.assertTrue(ret)
73
+ return ret
74
+
75
+ def setUp(self):
76
+ self.cgcleaner = pgnutils.CGCleaner()
77
+ self.maxDiff = None
78
+
79
+
80
+ if __name__ == "__main__":
81
+ unittest.main()