**AI disclosure (per AI_POLICY.md):** this was investigated and written with the assistance of Claude (Anthropic). I independently reproduced it against a fresh clone of `main` myself before filing — repro below, runnable standalone, no dependencies beyond Rich itself.
## Summary
A `Text` object's own `.justify` attribute is silently dropped when the `Text` is passed directly as a top-level argument to `Console.print()`, unless `justify=` is *also* passed to `print()` itself — even though `Text.__rich_console__` documents/implements `self.justify` as taking priority over the console-level default.
## Reproduction
```python
from rich.console import Console
from rich.text import Text
import io
buf1 = io.StringIO()
Console(file=buf1, width=20).print(Text("hi", justify="center"))
print(repr(buf1.getvalue()))
# -> 'hi\n' <- not centered, despite Text's own justify="center"
buf2 = io.StringIO()
Console(file=buf2, width=20).print(Text("hi", justify="center"), justify="center")
print(repr(buf2.getvalue()))
# -> ' hi \n' <- only works if justify is ALSO passed to print()
```
## Root cause
`Console._collect_renderables()` (`rich/console.py:1550-1554`, inside `check_text()`) funnels every `Text` object through:
```python
sep_text = Text(sep, justify=justify, end=end) # justify = print()'s own kwarg, default None
append(sep_text.join(text))
```
`Text.join()` (`rich/text.py:788`) builds the merged result via `self.blank_copy()`, where `self` is the *separator* `sep_text` — so the joined result inherits the **separator's** `justify`/`overflow`/`no_wrap`, silently clobbering whatever the joined-in `Text`'s own `.justify` was set to.
The same `Text` object centers correctly when wrapped in `Panel(...)` or `Group(...)`, because those containers call `console.render()` on the inner `Text` directly, bypassing this join path — so the bug is specific to passing a `Text` as a direct top-level argument to `Console.print()`.
## Checked
`gh search issues --repo Textualize/rich` for "justify" (30+ related hits reviewed) — found related-but-distinct issues (#460 `console.log` missing a `justify` kwarg entirely, fixed 2020; #3948/#4021 `Table` title justify with `soft_wrap`) but nothing matching this specific "`Text.justify` silently dropped by `print()`" defect. Appears unreported.
Happy to put together a PR (something like: preserve the joined item's own `justify`/`overflow`/`no_wrap` when it's a single `Text` and `print()`'s own `justify` wasn't explicitly passed) if this is confirmed as worth fixing.
Hi @willmcgugan / maintainers,
I've investigated this and created a fix with accompanying tests on branch `fix-console-print-text-justify`:
https://github.com/Vansh-Sharmaa/rich/tree/fix-console-print-text-justify
### Root Cause
In `Console._collect_renderables()` (`rich/console.py`), when `text` contains a single `Text` object, `sep_text = Text(sep, justify=justify, end=end)` constructs a separator with `justify=None` (if `print()` wasn't passed an explicit justify). Then `sep_text.join(text)` builds the result from `sep_text.blank_copy()`, resetting the `Text`'s own `justify`, `overflow`, and `no_wrap` to `None`.
### Proposed Fix
When `len(text) == 1`, initialize `sep_text` preserving `first_text.justify`, `first_text.overflow`, `first_text.no_wrap`, `first_text.tab_size`, and `first_text.style` (while allowing any explicit `justify` or other overrides passed to `print()` to take precedence).
PR interaction limits are currently enabled on the repository for non-collaborators, but the patch and unit tests are ready here:
https://github.com/Vansh-Sharmaa/rich/commit/d6dbb0968c07d18056c998f5f96522dd4ce2569e
Would you like me to open a PR if permissions allow, or would you prefer to pull the branch directly? Thanks!
Thanks for digging into this, @Vansh-Sharmaa — this matches what I found when filing the issue, and I ran your branch to confirm.
**Root cause check:** confirmed. `sep_text = Text(sep, justify=justify, end=end)` builds the separator with `justify=None` whenever `print()` isn't given an explicit `justify=`, and `Text.join()`'s use of `sep_text.blank_copy()` then stamps that (plus `overflow`/`no_wrap`) onto the joined result — clobbering the original `Text`'s own values. Your fix's extension to also preserve `overflow`, `no_wrap`, `tab_size`, and `style` is correct and more complete than my original report, which only called out `justify` explicitly — the same `blank_copy()` mechanism breaks those too.
**Independently verified, not just read:**
- Reproduced on current `main` (285d9e9) and on the released PyPI package (rich 15.0.0): `console.print(Text("hi", justify="center"))` at width 20 prints `'hi\n'`, not centered.
- Checked out `fix-console-print-text-justify` (d6dbb096) in the same environment: same call now prints `' hi \n'` — fixed.
- Ran the full `tests/test_console.py` suite against the fix branch: 96 passed, 7 skipped (pre-existing, unrelated), no regressions. Your three new tests (`test_print_text_justify`, `test_print_text_justify_override`, `test_print_text_overflow_and_no_wrap`) all pass, including the override case confirming an explicit `print(..., justify=...)` still correctly takes precedence over the `Text`'s own value.
- The scope limit (only touching the `len(text) == 1` path, leaving multi-`Text` joins on the old behavior) looks like the right conservative call — that path isn't part of what's reported here, and the existing multi-text join tests still pass unchanged.
Setup: Windows, Python 3.12.10, editable install from a fresh clone at each ref. Happy to share the exact repro/test commands if useful.
(Disclosure: my original report and this verification pass were done with AI-assisted tooling — Claude — reviewed and run by me before posting.)
Thanks so much for taking the time to test and verify the branch, @tritsystem! Really appreciate the detailed confirmation and regression checks across Python 3.12.
cc @willmcgugan — since repository interaction limits currently prevent non-collaborators from submitting pull requests directly, would you prefer to pull/cherry-pick commit `d6dbb0968c07d18056c998f5f96522dd4ce2569e` directly, or grant temporary contributor access so I can submit the PR via the standard review flow?
Branch: https://github.com/Vansh-Sharmaa/rich/tree/fix-console-print-text-justify
Commit: https://github.com/Vansh-Sharmaa/rich/commit/d6dbb0968c07d18056c998f5f96522dd4ce2569e
Thanks!
Took a look at this — agree with the diagnosis. `_collect_renderables` builds the join separator with `print()`'s `justify` (default `None`), and `Text.join` → `blank_copy()` then overwrites the `Text`'s own justify/overflow/no_wrap.
I'll open a small PR that preserves those attrs for the single-`Text` case, with `print(justify=...)` still winning when set.
Opened a fix branch (PR create is blocked for non-collaborators on this repo):
https://github.com/ShamikOfficial/rich/tree/fix-text-justify-print
Compare:
https://github.com/Textualize/rich/compare/main...ShamikOfficial:rich:fix-text-justify-print?expand=1
Single-`Text` path keeps justify/overflow/no_wrap/tab_size; `print(justify=...)` still overrides. `tests/test_console.py` green locally (96 passed, 7 skipped).