Skip to content

Reject bool max_length and non-str separator - #196

Merged
un33k merged 1 commit into
un33k:masterfrom
Pitchfork-and-Torch:cook/reject-bool-max-length-and-non-str-separator
Sep 18, 2026
Merged

un33k merged 1 commit into
un33k:masterfrom
Pitchfork-and-Torch:cook/reject-bool-max-length-and-non-str-separator

Conversation

@Pitchfork-and-Torch

Copy link
Copy Markdown
Contributor

Summary

max_length=True previously truncated to one character because bool is an int subclass. separator=None raised a cryptic replace() argument 2 must be str TypeError.

Validate types up front with clear TypeErrors. Nonpositive max_length remains unlimited per existing docs.

Test plan

  • python -m unittest test.TestSlugify.test_max_length_rejects_bool
  • slugify("Hello World", max_length=5) still returns hello

max_length=True previously truncated to one character because bool is an
int subclass. separator=None raised a cryptic replace() TypeError.
Validate types up front with clear TypeErrors.
@un33k

un33k commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Confirmed and merging. max_length=True was silently truncating to a single character because bool is an int subclass, and separator=None raised an opaque replace() TypeError. Up-front type validation is the right fix; nonpositive max_length still means unlimited per the docs, and this only rejects genuinely invalid input, so legacy output is unaffected. Thanks, @Pitchfork-and-Torch.

🚀 Generated with Dojo ⛩️

@un33k
un33k merged commit bc38822 into un33k:master Sep 18, 2026
@un33k

un33k commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Follow-up: after merging, we reverted this change (commit reverting #196 on master).

On reflection it runs against this project's hard compatibility rule: the legacy algorithm is frozen and its behavior must not change at all, even for unlikely input. This validation lives in the shared entry point, so it also altered legacy slugify('...', max_length=True) from returning 'h' to raising TypeError. That is a real legacy behavior change, so under our "legacy stays in the past" policy we can't take it on the legacy path — regardless of how questionable max_length=True is as input.

This is not a reflection on the fix quality; the diagnosis (bool being an int subclass) is correct and the errors are clearer. We'd gladly accept the same up-front type validation gated to algorithm='modern' only, leaving legacy output byte-identical. If you're up for it, a modern-only version would be very welcome. Thank you, @Pitchfork-and-Torch, and apologies for the round-trip.

🚀 Generated with Dojo ⛩️

un33k added a commit that referenced this pull request Sep 18, 2026
Move the legacy slug pipeline into a dedicated frozen module and make the
public slugify() a thin dispatcher: algorithm='legacy' (default) calls the
frozen _legacy implementation, algorithm='modern' runs the modern pipeline.
Relocate the existing up-front TypeError validation for bool/non-int
max_length and non-str separator (from #196) into the modern path only, so
legacy output is unchanged while modern keeps rejecting invalid types.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️
un33k added a commit that referenced this pull request Sep 18, 2026
Bump to 9.1.0. Modern-only: decode uppercase &#X..; hex references
(Rupayon Haldar, #195); preserve fitting post-replacement output during
truncation (emme1t, #193); relocate up-front argument type validation to
the modern path (Jon Bailey, #196). Fix add_uppercase_char atomicity
(Cristian Ramirez, #194). Legacy output unchanged.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️
un33k added a commit that referenced this pull request Sep 18, 2026
* Split frozen legacy pipeline into slugify/_legacy.py

Move the legacy slug pipeline into a dedicated frozen module and make the
public slugify() a thin dispatcher: algorithm='legacy' (default) calls the
frozen _legacy implementation, algorithm='modern' runs the modern pipeline.
Relocate the existing up-front TypeError validation for bool/non-int
max_length and non-str separator (from #196) into the modern path only, so
legacy output is unchanged while modern keeps rejecting invalid types.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️

* Reorganize tests under tests/ with frozen legacy suite

Move the test suite into tests/: the original upstream legacy suite becomes
the frozen tests/test_legacy.py (contents unchanged), mirroring the _legacy.py
code split, alongside tests/test_release.py and the add_uppercase test. The
modern-only bool/separator validation test moves to the modern suite. Update
pyproject testpaths, MANIFEST.in, and tox commands to the tests/ layout.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️

* Document legacy-frozen policy and split in DOJO.md and README

Record that legacy is architecturally frozen (slugify/_legacy.py and
tests/test_legacy.py) and that all new work targets algorithm='modern'.
Add a contributor note in the README not to open PRs that change legacy
output.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️

* Release 9.1.0: modern uppercase hex, truncation and validation fixes

Bump to 9.1.0. Modern-only: decode uppercase &#X..; hex references
(Rupayon Haldar, #195); preserve fitting post-replacement output during
truncation (emme1t, #193); relocate up-front argument type validation to
the modern path (Jon Bailey, #196). Fix add_uppercase_char atomicity
(Cristian Ramirez, #194). Legacy output unchanged.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️

* Fix release checks for 9.1.0 and tests/ layout

Update tools/check_dist.py to assert version 9.1.0 and the tests/ sdist
layout (tests/test_legacy.py, tests/test_release.py). Add coverage for
reachable branches in the split modules via the public API, restoring the
97% coverage gate without changing legacy behavior.

🚀 Generated with [Dojo](https://heydojo.ai) ⛩️
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants