Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
C
cpython
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
cpython
Commits
acc9f3fb
Kaydet (Commit)
acc9f3fb
authored
Eki 15, 2013
tarafından
Serhiy Storchaka
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Issue #18725: The textwrap module now supports truncating multiline text.
üst
bc2bfa6b
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
165 additions
and
58 deletions
+165
-58
textwrap.rst
Doc/library/textwrap.rst
+16
-12
test_textwrap.py
Lib/test/test_textwrap.py
+98
-7
textwrap.py
Lib/textwrap.py
+49
-39
NEWS
Misc/NEWS
+2
-0
No files found.
Doc/library/textwrap.rst
Dosyayı görüntüle @
acc9f3fb
...
@@ -250,6 +250,22 @@ hyphenated words; only then will long words be broken if necessary, unless
...
@@ -250,6 +250,22 @@ hyphenated words; only then will long words be broken if necessary, unless
was to always allow breaking hyphenated words.
was to always allow breaking hyphenated words.
.. attribute:: max_lines
(default: ``None``) If not ``None``, then the text be will truncated to
*max_lines* lines.
.. versionadded:: 3.4
.. attribute:: placeholder
(default: ``' [...]'``) String that will be appended to the last line of
text if it will be truncated.
.. versionadded:: 3.4
:class:`TextWrapper` also provides some public methods, analogous to the
:class:`TextWrapper` also provides some public methods, analogous to the
module-level convenience functions:
module-level convenience functions:
...
@@ -266,15 +282,3 @@ hyphenated words; only then will long words be broken if necessary, unless
...
@@ -266,15 +282,3 @@ hyphenated words; only then will long words be broken if necessary, unless
Wraps the single paragraph in *text*, and returns a single string
Wraps the single paragraph in *text*, and returns a single string
containing the wrapped paragraph.
containing the wrapped paragraph.
.. function:: shorten(text, *, placeholder=" [...]")
Collapse and truncate the given text to fit in :attr:`width`
characters.
The text first has its whitespace collapsed. If it then fits in
:attr:`width`, it is returned as-is. Otherwise, as many words
as possible are joined and then the *placeholder* is appended.
.. versionadded:: 3.4
Lib/test/test_textwrap.py
Dosyayı görüntüle @
acc9f3fb
...
@@ -42,10 +42,6 @@ class BaseTestCase(unittest.TestCase):
...
@@ -42,10 +42,6 @@ class BaseTestCase(unittest.TestCase):
"
\n
expected
%
r
\n
"
"
\n
expected
%
r
\n
"
"but got
%
r"
%
(
expect
,
result
))
"but got
%
r"
%
(
expect
,
result
))
def
check_shorten
(
self
,
text
,
width
,
expect
,
**
kwargs
):
result
=
shorten
(
text
,
width
,
**
kwargs
)
self
.
check
(
result
,
expect
)
class
WrapTestCase
(
BaseTestCase
):
class
WrapTestCase
(
BaseTestCase
):
...
@@ -433,6 +429,90 @@ What a mess!
...
@@ -433,6 +429,90 @@ What a mess!
self
.
check_wrap
(
text
,
7
,
[
"aa
\xe4\xe4
-"
,
"
\xe4\xe4
"
])
self
.
check_wrap
(
text
,
7
,
[
"aa
\xe4\xe4
-"
,
"
\xe4\xe4
"
])
class
MaxLinesTestCase
(
BaseTestCase
):
text
=
"Hello there, how are you this fine day? I'm glad to hear it!"
def
test_simple
(
self
):
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello [...]"
],
max_lines
=
0
)
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello [...]"
],
max_lines
=
1
)
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello there,"
,
"how [...]"
],
max_lines
=
2
)
self
.
check_wrap
(
self
.
text
,
13
,
[
"Hello there,"
,
"how are [...]"
],
max_lines
=
2
)
self
.
check_wrap
(
self
.
text
,
80
,
[
self
.
text
],
max_lines
=
1
)
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello there,"
,
"how are you"
,
"this fine"
,
"day? I'm"
,
"glad to hear"
,
"it!"
],
max_lines
=
6
)
def
test_spaces
(
self
):
# strip spaces before placeholder
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello there,"
,
"how are you"
,
"this fine"
,
"day? [...]"
],
max_lines
=
4
)
# placeholder at the start of line
self
.
check_wrap
(
self
.
text
,
6
,
[
"Hello"
,
"[...]"
],
max_lines
=
2
)
# final spaces
self
.
check_wrap
(
self
.
text
+
' '
*
10
,
12
,
[
"Hello there,"
,
"how are you"
,
"this fine"
,
"day? I'm"
,
"glad to hear"
,
"it!"
],
max_lines
=
6
)
def
test_placeholder
(
self
):
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello..."
],
max_lines
=
1
,
placeholder
=
'...'
)
self
.
check_wrap
(
self
.
text
,
12
,
[
"Hello there,"
,
"how are..."
],
max_lines
=
2
,
placeholder
=
'...'
)
# long placeholder and indentation
with
self
.
assertRaises
(
ValueError
):
wrap
(
self
.
text
,
16
,
initial_indent
=
' '
,
max_lines
=
1
,
placeholder
=
' [truncated]...'
)
with
self
.
assertRaises
(
ValueError
):
wrap
(
self
.
text
,
16
,
subsequent_indent
=
' '
,
max_lines
=
2
,
placeholder
=
' [truncated]...'
)
self
.
check_wrap
(
self
.
text
,
16
,
[
" Hello there,"
,
" [truncated]..."
],
max_lines
=
2
,
initial_indent
=
' '
,
subsequent_indent
=
' '
,
placeholder
=
' [truncated]...'
)
self
.
check_wrap
(
self
.
text
,
16
,
[
" [truncated]..."
],
max_lines
=
1
,
initial_indent
=
' '
,
subsequent_indent
=
' '
,
placeholder
=
' [truncated]...'
)
self
.
check_wrap
(
self
.
text
,
80
,
[
self
.
text
],
placeholder
=
'.'
*
1000
)
class
LongWordTestCase
(
BaseTestCase
):
class
LongWordTestCase
(
BaseTestCase
):
def
setUp
(
self
):
def
setUp
(
self
):
self
.
wrapper
=
TextWrapper
()
self
.
wrapper
=
TextWrapper
()
...
@@ -493,6 +573,14 @@ How *do* you spell that odd word, anyways?
...
@@ -493,6 +573,14 @@ How *do* you spell that odd word, anyways?
result
=
wrap
(
self
.
text
,
width
=
30
,
break_long_words
=
0
)
result
=
wrap
(
self
.
text
,
width
=
30
,
break_long_words
=
0
)
self
.
check
(
result
,
expect
)
self
.
check
(
result
,
expect
)
def
test_max_lines_long
(
self
):
self
.
check_wrap
(
self
.
text
,
12
,
[
'Did you say '
,
'"supercalifr'
,
'agilisticexp'
,
'[...]'
],
max_lines
=
4
)
class
IndentTestCases
(
BaseTestCase
):
class
IndentTestCases
(
BaseTestCase
):
...
@@ -782,6 +870,10 @@ class IndentTestCase(unittest.TestCase):
...
@@ -782,6 +870,10 @@ class IndentTestCase(unittest.TestCase):
class
ShortenTestCase
(
BaseTestCase
):
class
ShortenTestCase
(
BaseTestCase
):
def
check_shorten
(
self
,
text
,
width
,
expect
,
**
kwargs
):
result
=
shorten
(
text
,
width
,
**
kwargs
)
self
.
check
(
result
,
expect
)
def
test_simple
(
self
):
def
test_simple
(
self
):
# Simple case: just words, spaces, and a bit of punctuation
# Simple case: just words, spaces, and a bit of punctuation
text
=
"Hello there, how are you this fine day? I'm glad to hear it!"
text
=
"Hello there, how are you this fine day? I'm glad to hear it!"
...
@@ -825,10 +917,9 @@ class ShortenTestCase(BaseTestCase):
...
@@ -825,10 +917,9 @@ class ShortenTestCase(BaseTestCase):
self
.
check_shorten
(
"hello world! "
,
10
,
"[...]"
)
self
.
check_shorten
(
"hello world! "
,
10
,
"[...]"
)
def
test_width_too_small_for_placeholder
(
self
):
def
test_width_too_small_for_placeholder
(
self
):
wrapper
=
TextWrapper
(
width
=
8
)
shorten
(
"x"
*
20
,
width
=
8
,
placeholder
=
"(......)"
)
wrapper
.
shorten
(
"x"
*
20
,
placeholder
=
"(......)"
)
with
self
.
assertRaises
(
ValueError
):
with
self
.
assertRaises
(
ValueError
):
wrapper
.
shorten
(
"x"
*
20
,
placeholder
=
"(.......)"
)
shorten
(
"x"
*
20
,
width
=
8
,
placeholder
=
"(.......)"
)
def
test_first_word_too_long_but_placeholder_fits
(
self
):
def
test_first_word_too_long_but_placeholder_fits
(
self
):
self
.
check_shorten
(
"Helloo"
,
5
,
"[...]"
)
self
.
check_shorten
(
"Helloo"
,
5
,
"[...]"
)
...
...
Lib/textwrap.py
Dosyayı görüntüle @
acc9f3fb
...
@@ -19,8 +19,6 @@ __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent']
...
@@ -19,8 +19,6 @@ __all__ = ['TextWrapper', 'wrap', 'fill', 'dedent', 'indent']
# since 0xa0 is not in range(128).
# since 0xa0 is not in range(128).
_whitespace
=
'
\t\n\x0b\x0c\r
'
_whitespace
=
'
\t\n\x0b\x0c\r
'
_default_placeholder
=
' [...]'
class
TextWrapper
:
class
TextWrapper
:
"""
"""
Object for wrapping/filling text. The public interface consists of
Object for wrapping/filling text. The public interface consists of
...
@@ -64,6 +62,10 @@ class TextWrapper:
...
@@ -64,6 +62,10 @@ class TextWrapper:
compound words.
compound words.
drop_whitespace (default: true)
drop_whitespace (default: true)
Drop leading and trailing whitespace from lines.
Drop leading and trailing whitespace from lines.
max_lines (default: None)
Truncate wrapped lines.
placeholder (default: ' [...]')
Append to the last line of truncated text.
"""
"""
unicode_whitespace_trans
=
{}
unicode_whitespace_trans
=
{}
...
@@ -106,7 +108,10 @@ class TextWrapper:
...
@@ -106,7 +108,10 @@ class TextWrapper:
break_long_words
=
True
,
break_long_words
=
True
,
drop_whitespace
=
True
,
drop_whitespace
=
True
,
break_on_hyphens
=
True
,
break_on_hyphens
=
True
,
tabsize
=
8
):
tabsize
=
8
,
*
,
max_lines
=
None
,
placeholder
=
' [...]'
):
self
.
width
=
width
self
.
width
=
width
self
.
initial_indent
=
initial_indent
self
.
initial_indent
=
initial_indent
self
.
subsequent_indent
=
subsequent_indent
self
.
subsequent_indent
=
subsequent_indent
...
@@ -117,6 +122,8 @@ class TextWrapper:
...
@@ -117,6 +122,8 @@ class TextWrapper:
self
.
drop_whitespace
=
drop_whitespace
self
.
drop_whitespace
=
drop_whitespace
self
.
break_on_hyphens
=
break_on_hyphens
self
.
break_on_hyphens
=
break_on_hyphens
self
.
tabsize
=
tabsize
self
.
tabsize
=
tabsize
self
.
max_lines
=
max_lines
self
.
placeholder
=
placeholder
# -- Private methods -----------------------------------------------
# -- Private methods -----------------------------------------------
...
@@ -225,6 +232,13 @@ class TextWrapper:
...
@@ -225,6 +232,13 @@ class TextWrapper:
lines
=
[]
lines
=
[]
if
self
.
width
<=
0
:
if
self
.
width
<=
0
:
raise
ValueError
(
"invalid width
%
r (must be > 0)"
%
self
.
width
)
raise
ValueError
(
"invalid width
%
r (must be > 0)"
%
self
.
width
)
if
self
.
max_lines
is
not
None
:
if
self
.
max_lines
>
1
:
indent
=
self
.
subsequent_indent
else
:
indent
=
self
.
initial_indent
if
len
(
indent
)
+
len
(
self
.
placeholder
.
lstrip
())
>
self
.
width
:
raise
ValueError
(
"placeholder too large for max width"
)
# Arrange in reverse order so items can be efficiently popped
# Arrange in reverse order so items can be efficiently popped
# from a stack of chucks.
# from a stack of chucks.
...
@@ -267,15 +281,41 @@ class TextWrapper:
...
@@ -267,15 +281,41 @@ class TextWrapper:
# fit on *any* line (not just this one).
# fit on *any* line (not just this one).
if
chunks
and
len
(
chunks
[
-
1
])
>
width
:
if
chunks
and
len
(
chunks
[
-
1
])
>
width
:
self
.
_handle_long_word
(
chunks
,
cur_line
,
cur_len
,
width
)
self
.
_handle_long_word
(
chunks
,
cur_line
,
cur_len
,
width
)
cur_len
=
sum
(
map
(
len
,
cur_line
))
# If the last chunk on this line is all whitespace, drop it.
# If the last chunk on this line is all whitespace, drop it.
if
self
.
drop_whitespace
and
cur_line
and
cur_line
[
-
1
]
.
strip
()
==
''
:
if
self
.
drop_whitespace
and
cur_line
and
cur_line
[
-
1
]
.
strip
()
==
''
:
cur_len
-=
len
(
cur_line
[
-
1
])
del
cur_line
[
-
1
]
del
cur_line
[
-
1
]
# Convert current line back to a string and store it in list
# of all lines (return value).
if
cur_line
:
if
cur_line
:
lines
.
append
(
indent
+
''
.
join
(
cur_line
))
if
(
self
.
max_lines
is
None
or
len
(
lines
)
+
1
<
self
.
max_lines
or
(
not
chunks
or
self
.
drop_whitespace
and
len
(
chunks
)
==
1
and
not
chunks
[
0
]
.
strip
())
and
cur_len
<=
width
):
# Convert current line back to a string and store it in
# list of all lines (return value).
lines
.
append
(
indent
+
''
.
join
(
cur_line
))
else
:
while
cur_line
:
if
(
cur_line
[
-
1
]
.
strip
()
and
cur_len
+
len
(
self
.
placeholder
)
<=
width
):
cur_line
.
append
(
self
.
placeholder
)
lines
.
append
(
indent
+
''
.
join
(
cur_line
))
break
cur_len
-=
len
(
cur_line
[
-
1
])
del
cur_line
[
-
1
]
else
:
if
lines
:
prev_line
=
lines
[
-
1
]
.
rstrip
()
if
(
len
(
prev_line
)
+
len
(
self
.
placeholder
)
<=
self
.
width
):
lines
[
-
1
]
=
prev_line
+
self
.
placeholder
break
lines
.
append
(
indent
+
self
.
placeholder
.
lstrip
())
break
return
lines
return
lines
...
@@ -308,36 +348,6 @@ class TextWrapper:
...
@@ -308,36 +348,6 @@ class TextWrapper:
"""
"""
return
"
\n
"
.
join
(
self
.
wrap
(
text
))
return
"
\n
"
.
join
(
self
.
wrap
(
text
))
def
shorten
(
self
,
text
,
*
,
placeholder
=
_default_placeholder
):
"""shorten(text: str) -> str
Collapse and truncate the given text to fit in 'self.width' columns.
"""
max_length
=
self
.
width
if
max_length
<
len
(
placeholder
.
strip
()):
raise
ValueError
(
"placeholder too large for max width"
)
sep
=
' '
sep_len
=
len
(
sep
)
parts
=
[]
cur_len
=
0
chunks
=
self
.
_split_chunks
(
text
)
for
chunk
in
chunks
:
if
not
chunk
.
strip
():
continue
chunk_len
=
len
(
chunk
)
+
sep_len
if
parts
else
len
(
chunk
)
if
cur_len
+
chunk_len
>
max_length
:
break
parts
.
append
(
chunk
)
cur_len
+=
chunk_len
else
:
# No truncation necessary
return
sep
.
join
(
parts
)
max_truncated_length
=
max_length
-
len
(
placeholder
)
while
parts
and
cur_len
>
max_truncated_length
:
last
=
parts
.
pop
()
cur_len
-=
len
(
last
)
+
sep_len
return
(
sep
.
join
(
parts
)
+
placeholder
)
.
strip
()
# -- Convenience interface ---------------------------------------------
# -- Convenience interface ---------------------------------------------
...
@@ -366,7 +376,7 @@ def fill(text, width=70, **kwargs):
...
@@ -366,7 +376,7 @@ def fill(text, width=70, **kwargs):
w
=
TextWrapper
(
width
=
width
,
**
kwargs
)
w
=
TextWrapper
(
width
=
width
,
**
kwargs
)
return
w
.
fill
(
text
)
return
w
.
fill
(
text
)
def
shorten
(
text
,
width
,
*
,
placeholder
=
_default_placeholder
,
*
*
kwargs
):
def
shorten
(
text
,
width
,
**
kwargs
):
"""Collapse and truncate the given text to fit in the given width.
"""Collapse and truncate the given text to fit in the given width.
The text first has its whitespace collapsed. If it then fits in
The text first has its whitespace collapsed. If it then fits in
...
@@ -378,8 +388,8 @@ def shorten(text, width, *, placeholder=_default_placeholder, **kwargs):
...
@@ -378,8 +388,8 @@ def shorten(text, width, *, placeholder=_default_placeholder, **kwargs):
>>> textwrap.shorten("Hello world!", width=11)
>>> textwrap.shorten("Hello world!", width=11)
'Hello [...]'
'Hello [...]'
"""
"""
w
=
TextWrapper
(
width
=
width
,
**
kwargs
)
w
=
TextWrapper
(
width
=
width
,
max_lines
=
1
,
**
kwargs
)
return
w
.
shorten
(
text
,
placeholder
=
placeholder
)
return
w
.
fill
(
' '
.
join
(
text
.
strip
()
.
split
())
)
# -- Loosely related functionality -------------------------------------
# -- Loosely related functionality -------------------------------------
...
...
Misc/NEWS
Dosyayı görüntüle @
acc9f3fb
...
@@ -42,6 +42,8 @@ Core and Builtins
...
@@ -42,6 +42,8 @@ Core and Builtins
Library
Library
-------
-------
- Issue #18725: The textwrap module now supports truncating multiline text.
- Issue #18776: atexit callbacks now display their full traceback when they
- Issue #18776: atexit callbacks now display their full traceback when they
raise an exception.
raise an exception.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment