Skip to content

Commit 043cddf

Browse files
Fix missing f-strings, deprecated datetime, stale pylint directives
- Add f-prefix to three RuntimeError format strings in attributes.py that were printing literal {self.name} instead of the attribute name - Replace deprecated datetime.utcnow() with datetime.now(timezone.utc) in all four export functions - Update hardcoded version fallback from 1.1.0 to 2.0.0 and narrow bare except to except Exception in exporters.py - Remove obsolete pylint no-self-use directives from reporting.py and iznn/__init__.py Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1250922 commit 043cddf

File tree

5 files changed

+60
-19
lines changed

5 files changed

+60
-19
lines changed

neat/attributes.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def validate(self, config):
8686
min_value = getattr(config, self.min_value_name)
8787
max_value = getattr(config, self.max_value_name)
8888
if max_value < min_value:
89-
raise RuntimeError("Invalid min/max configuration for {self.name}")
89+
raise RuntimeError(f"Invalid min/max configuration for {self.name}")
9090

9191

9292
class IntegerAttribute(BaseAttribute):
@@ -130,7 +130,7 @@ def validate(self, config):
130130
min_value = getattr(config, self.min_value_name)
131131
max_value = getattr(config, self.max_value_name)
132132
if max_value < min_value:
133-
raise RuntimeError("Invalid min/max configuration for {self.name}")
133+
raise RuntimeError(f"Invalid min/max configuration for {self.name}")
134134

135135

136136
class BoolAttribute(BaseAttribute):
@@ -174,7 +174,7 @@ def mutate_value(self, value, config):
174174
def validate(self, config):
175175
default = str(getattr(config, self.default_name)).lower()
176176
if default not in ('1', 'on', 'yes', 'true', '0', 'off', 'no', 'false', 'random', 'none'):
177-
raise RuntimeError("Invalid default value for {self.name}")
177+
raise RuntimeError(f"Invalid default value for {self.name}")
178178

179179

180180
class StringAttribute(BaseAttribute):

neat/export/exporters.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
NEAT network (FeedForward, Recurrent, CTRNN, IZNN) to the JSON format.
66
"""
77

8-
from datetime import datetime
8+
from datetime import datetime, timezone
99
from .json_format import FORMAT_VERSION, get_function_info
1010

1111

@@ -15,9 +15,9 @@ def _get_neat_version():
1515
import neat
1616
if hasattr(neat, '__version__'):
1717
return neat.__version__
18-
return "1.1.0"
19-
except:
20-
return "1.1.0"
18+
return "2.0.0"
19+
except Exception:
20+
return "2.0.0"
2121

2222

2323
def export_feedforward(network, metadata=None):
@@ -72,7 +72,7 @@ def export_feedforward(network, metadata=None):
7272
"format_version": FORMAT_VERSION,
7373
"network_type": "feedforward",
7474
"metadata": {
75-
"created_timestamp": datetime.utcnow().isoformat() + "Z",
75+
"created_timestamp": datetime.now(timezone.utc).isoformat(),
7676
"neat_python_version": _get_neat_version(),
7777
},
7878
"topology": {
@@ -84,11 +84,11 @@ def export_feedforward(network, metadata=None):
8484
"nodes": nodes,
8585
"connections": connections
8686
}
87-
87+
8888
# Add optional metadata if provided
8989
if metadata:
9090
data["metadata"].update(metadata)
91-
91+
9292
return data
9393

9494

@@ -144,7 +144,7 @@ def export_recurrent(network, metadata=None):
144144
"format_version": FORMAT_VERSION,
145145
"network_type": "recurrent",
146146
"metadata": {
147-
"created_timestamp": datetime.utcnow().isoformat() + "Z",
147+
"created_timestamp": datetime.now(timezone.utc).isoformat(),
148148
"neat_python_version": _get_neat_version(),
149149
},
150150
"topology": {
@@ -156,11 +156,11 @@ def export_recurrent(network, metadata=None):
156156
"nodes": nodes,
157157
"connections": connections
158158
}
159-
159+
160160
# Add optional metadata if provided
161161
if metadata:
162162
data["metadata"].update(metadata)
163-
163+
164164
return data
165165

166166

@@ -218,7 +218,7 @@ def export_ctrnn(network, metadata=None):
218218
"format_version": FORMAT_VERSION,
219219
"network_type": "ctrnn",
220220
"metadata": {
221-
"created_timestamp": datetime.utcnow().isoformat() + "Z",
221+
"created_timestamp": datetime.now(timezone.utc).isoformat(),
222222
"neat_python_version": _get_neat_version(),
223223
},
224224
"topology": {
@@ -230,11 +230,11 @@ def export_ctrnn(network, metadata=None):
230230
"nodes": nodes,
231231
"connections": connections
232232
}
233-
233+
234234
# Add optional metadata if provided
235235
if metadata:
236236
data["metadata"].update(metadata)
237-
237+
238238
return data
239239

240240

@@ -298,7 +298,7 @@ def export_iznn(network, metadata=None):
298298
"format_version": FORMAT_VERSION,
299299
"network_type": "iznn",
300300
"metadata": {
301-
"created_timestamp": datetime.utcnow().isoformat() + "Z",
301+
"created_timestamp": datetime.now(timezone.utc).isoformat(),
302302
"neat_python_version": _get_neat_version(),
303303
},
304304
"topology": {

neat/iznn/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ def reset(self):
147147
n.reset()
148148

149149
def get_time_step_msec(self):
150-
# pylint: disable=no-self-use
151150
# TODO: Investigate performance or numerical stability issues that may
152151
# result from using this hard-coded time step.
153152
return 0.05

neat/reporting.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ def end_generation(self, config, population, species_set):
128128
print(f"Generation time: {elapsed:.3f} sec")
129129

130130
def post_evaluate(self, config, population, species, best_genome):
131-
# pylint: disable=no-self-use
132131
fitnesses = [c.fitness for c in population.values()]
133132
fit_mean = mean(fitnesses)
134133
fit_std = stdev(fitnesses)

progress-20260314.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Progress Log — 2026-03-14
2+
3+
## Code quality review and bug fixes
4+
5+
Performed a full code review of the neat-python codebase, scanning all core modules for defects, typos, stale comments, and quality issues. Identified 11 issues total; fixed 5 in this session.
6+
7+
### Fixed: Missing f-string prefixes in attribute validation (attributes.py)
8+
9+
Three `raise RuntimeError(...)` calls in `FloatAttribute.validate`, `IntegerAttribute.validate`, and `BoolAttribute.validate` were plain strings instead of f-strings, so error messages would print the literal text `{self.name}` instead of the attribute name.
10+
11+
- `neat/attributes.py:89` — FloatAttribute
12+
- `neat/attributes.py:133` — IntegerAttribute
13+
- `neat/attributes.py:177` — BoolAttribute
14+
15+
### Fixed: Hardcoded fallback version and bare except in exporters (export/exporters.py)
16+
17+
`_get_neat_version()` had a hardcoded fallback of `"1.1.0"` but the project version is `2.0.0`. Also used a bare `except:` clause which catches SystemExit, KeyboardInterrupt, etc. Changed fallback to `"2.0.0"` and narrowed to `except Exception:`.
18+
19+
### Fixed: Deprecated datetime.utcnow() in exporters (export/exporters.py)
20+
21+
All four exporter functions (`export_feedforward`, `export_recurrent`, `export_ctrnn`, `export_iznn`) used `datetime.utcnow().isoformat() + "Z"` which is deprecated since Python 3.12. Replaced with `datetime.now(timezone.utc).isoformat()` which produces a timezone-aware ISO 8601 string with `+00:00` suffix.
22+
23+
### Fixed: Obsolete pylint directives (reporting.py, iznn/__init__.py)
24+
25+
Removed `# pylint: disable=no-self-use` comments from two locations. The `no-self-use` check was removed from pylint in version 2.14.
26+
27+
- `neat/reporting.py:131` — StdOutReporter.post_evaluate
28+
- `neat/iznn/__init__.py:150` — IZNN.get_time_step_msec
29+
30+
### Other issues identified but not yet fixed
31+
32+
1. **Destructive pickling side effects**`DefaultGenomeConfig.__getstate__` and `DefaultSpeciesSet.__getstate__` call `next()` on `itertools.count` objects, advancing the counter on the original object.
33+
2. **FeedForwardNetwork.create mutates genome** — Writing to `cg.weight` when `random_values` or `unique_value` is set corrupts the genome. Also `if unique_value:` is falsy for 0.0.
34+
3. **best_genome tracking ignores fitness_criterion** — Always uses `>` even when `fitness_criterion = min`.
35+
4. **fitness_criterion attribute may not be set** — When `no_fitness_termination=True` and criterion is not max/min/mean.
36+
5. **Dead None check in stagnation.py:56**`prev_fitness` can never be None.
37+
6. **Weaker connection filter in RecurrentNetwork/CTRNN** — Should match the stricter filter used by IZNN.
38+
39+
### Files modified
40+
- `neat/attributes.py`
41+
- `neat/export/exporters.py`
42+
- `neat/reporting.py`
43+
- `neat/iznn/__init__.py`

0 commit comments

Comments
 (0)