473,695 Members | 2,951 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

textwrap.dedent replaces tabs?

The documentation for dedent says, "Remove any whitespace than can be
uniformly removed from the left of every line in `text`", yet I'm
finding that it's also modifying the '\t' characters, which is highly
undesirable in my application. Is there any way to stop it from doing
this, or alternatively, to put those tabs back in?

I see that TextWrap and its member functions take an 'expand_tabs'
kwarg, but dedent unfortunately does not.

....I suppose such a function (replacement dedent) isn't terribly tough
to write, but it seems an odd default especially considering there's no
way to turn off the undesired changes, but were the changes /not/ made,
the same text could just be passed through TextWrapper and have them
removed...

thx,
-tom!

--
Dec 16 '06 #1
15 2912
Hmmm... a quick fix might be to temporarily replace all tab characters
with another, relatively unused control character.

MyString = MyString.replac e("\t", chr(1))
MyString = textwrap.dedent (MyString)
MyString = MyString.replac e(chr(1), "\t")

Of course... this isn't exactly safe, but it's not going to be fatal,
if it does mess something up. As long as you don't expect receiving any
ASCII 1 characters.

Dec 16 '06 #2
CakeProphet wrote:
Hmmm... a quick fix might be to temporarily replace all tab characters
with another, relatively unused control character.

MyString = MyString.replac e("\t", chr(1))
MyString = textwrap.dedent (MyString)
MyString = MyString.replac e(chr(1), "\t")

Of course... this isn't exactly safe, but it's not going to be fatal,
if it does mess something up. As long as you don't expect receiving any
ASCII 1 characters.
Well, there is that small problem that there are leading tabs that I
want stripped. I guess I could manually replace all tabs with eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.

It's not that I don't understand /why/ it does it; indeed I'm sure it
does this so you can mix tabs and spaces in Python source. Why anyone
would intentionally do that, though, I'm not sure. ;)

-tom!

--
Dec 17 '06 #3
Tom Plunket wrote:
I*guess*I*could *manually*repla ce*all*tabs*wit h*eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.
You mean, as easy as
>>"\talpha\tbet a\t".expandtabs ()
' alpha beta '

?

Peter

Dec 17 '06 #4
Tom Plunket wrote:
CakeProphet wrote:

>Hmmm... a quick fix might be to temporarily replace all tab characters
with another, relatively unused control character.

MyString = MyString.replac e("\t", chr(1))
MyString = textwrap.dedent (MyString)
MyString = MyString.replac e(chr(1), "\t")

Of course... this isn't exactly safe, but it's not going to be fatal,
if it does mess something up. As long as you don't expect receiving any
ASCII 1 characters.

Well, there is that small problem that there are leading tabs that I
want stripped. I guess I could manually replace all tabs with eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.

It's not that I don't understand /why/ it does it; indeed I'm sure it
does this so you can mix tabs and spaces in Python source. Why anyone
would intentionally do that, though, I'm not sure. ;)

-tom!

This should do the trick:
>>Dedent = re.compile ('^\s+')
for line in lines: print Dedent.sub ('', line)
Frederic

-----------------------------------------------------------------------

Testing:
>>text = s = ''' # Dedent demo
No indent
Three space indent
\tOne tab indent
\t\tThree space, two tab indent
\t \tOne tab, two space, one tab indent with two tabs here >\t\t<'''
>>print text
print s
# Dedent demo
No indent
Three space indent
One tab indent
Three space - two tab indent
One tab - two spaces - one tab indent with two tabs here >
<
>>for line in text.splitlines (): print Dedent.sub ('', line)
# Dedent demo
No indent
Three space indent
One tab indent
Three space - two tab indent
One tab - two spaces - one tab indent with two tabs here <

-----------------------------------------------------------------------
Dec 17 '06 #5
Peter Otten wrote:
I*guess*I*could *manually*repla ce*all*tabs*wit h*eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.

You mean, as easy as
>"\talpha\tbeta \t".expandtabs( )
' alpha beta '

?
Umm, no, that's why I wrote "eight spaces (as opposed to 'correct' tab
stops)".

In either case, though, it'd be hard to know how to replace the tabs, so
it'd be better not to remove them in the first place. Indeed, dedent()
would work perfectly for my cases if it simply didn't do the
expandtabs() in the first place, but there'd be some pretty glaring
holes in its logic then.

I've since written up a fairly reasonable (IMO) replacement though, that
started with textwrap.dedent (), removed the expandtabs() call, and
Does The Right Thing with tabs vs. spaces (e.g. it doesn't treat a tab
at the beginning of a line as the same as eight spaces).
-tom!

--
Dec 19 '06 #6
Frederic Rentsch wrote:
Well, there is that small problem that there are leading tabs that I
want stripped. I guess I could manually replace all tabs with eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.

This should do the trick:
>>Dedent = re.compile ('^\s+')
>>for line in lines: print Dedent.sub ('', line)
The fact that this doesn't do what dedent() does makes it not useful.
Stripping all leading spaces from text is as easy as calling lstrip() on
each line:

text = '\n'.join([line.lstrip() for line in text.split('\n' )])

alas, that isn't what I am looking for, nor is that what
textwrap.dedent () is intended to do.

-tom!

--
Dec 19 '06 #7
Tom Plunket wrote:
Frederic Rentsch wrote:

>>Well, there is that small problem that there are leading tabs that I
want stripped. I guess I could manually replace all tabs with eight
spaces (as opposed to 'correct' tab stops), and then replace them when
done, but it's probably just as easy to write a non-destructive dedent.
This should do the trick:
> >>Dedent = re.compile ('^\s+')
for line in lines: print Dedent.sub ('', line)

The fact that this doesn't do what dedent() does makes it not useful.
Stripping all leading spaces from text is as easy as calling lstrip() on
each line:
My goodness! How right your are.
text = '\n'.join([line.lstrip() for line in text.split('\n' )])

alas, that isn't what I am looking for, nor is that what
textwrap.dedent () is intended to do.

-tom!

Following a call to dedent () it shouldn't be hard to translate leading
groups of so many spaces back to tabs. But this is probably not what you
want. If I understand your problem, you want to restore the dedented
line to its original composition if spaces and tabs are mixed and this
doesn't work because the information doesn't survive dedent (). Could
the information perhaps be passed around dedent ()? Like this: make a
copy of your lines and translate the copy's tabs to so many (8?) marker
bytes (e.g. ascii 0). Dedent the originals. Left-strip each of the
marked line copies to the length of its dedented original and translate
the marked groups back to tabs.

Frederic
Dec 22 '06 #8
Frederic Rentsch wrote:
Following a call to dedent () it shouldn't be hard to translate leading
groups of so many spaces back to tabs.
Sure, but the point is more that I don't think it's valid to change to
tabs in the first place.

E.g.:

input = ' ' + '\t' + 'hello\n' +
'\t' + 'world'

output = textwrap.dedent (input)

will yield all of the leading whitespace stripped, which IMHO is a
violation of its stated function. In this case, nothing should be
stripped, because the leading whitespace in these two lines does not
/actually/ match. Sure, it visually matches, but that's not the point
(although I can understand that that's a point of contention in the
interpreter anyway, I would have no problem with it not accepting "1 tab
= 8 spaces" for indentation... But that's another holy war.
If I understand your problem, you want to restore the dedented line to
its original composition if spaces and tabs are mixed and this doesn't
work because the information doesn't survive dedent ().
Sure, although would there be a case to be made to simply not strip the
tabs in the first place?

Like this, keeping current functionality and everything... (although I
would think if someone wanted tabs expanded, they'd call expandtabs on
the input before calling the function!):

def dedent(text, expand_tabs=Tru e):
"""dedent(t ext : string, expand_tabs : bool) -string

Remove any whitespace than can be uniformly removed from the left
of every line in `text`, optionally expanding tabs before altering
the text.

This can be used e.g. to make triple-quoted strings line up with
the left edge of screen/whatever, while still presenting it in the
source code in indented form.

For example:

def test():
# end first line with \ to avoid the empty line!
s = '''\
hello
\t world
'''
print repr(s) # prints ' hello\n \t world\n '
print repr(dedent(s)) # prints ' hello\n\t world\n'
"""
if expand_tabs:
text = text.expandtabs ()
lines = text.split('\n' )

margin = None
for line in lines:
if margin is None:
content = line.lstrip()
if not content:
continue
indent = len(line) - len(content)
margin = line[:indent]
elif not line.startswith (margin):
if len(line) < len(margin):
content = line.lstrip()
if not content:
continue
while not line.startswith (margin):
margin = margin[:-1]

if margin is not None and len(margin) 0:
margin = len(margin)
for i in range(len(lines )):
lines[i] = lines[i][margin:]

return '\n'.join(lines )

import unittest

class DedentTest(unit test.TestCase):
def testBasicWithSp aces(self):
input = "\n Hello\n World"
expected = "\nHello\n World"
self.failUnless Equal(expected, dedent(input))

def testBasicWithTa bLeadersSpacesI nside(self):
input = "\n\tHello\ n\t World"
expected = "\nHello\n World"
self.failUnless Equal(expected, dedent(input, False))

def testAllTabs(sel f):
input = "\t\tHello\n\tW orld"
expected = "\tHello\nWorld "
self.failUnless Equal(expected, dedent(input, False))

def testFirstLineNo tIndented(self) :
input = "Hello\n\tWorld "
expected = input
self.failUnless Equal(expected, dedent(input, False))

def testMixedTabsAn dSpaces(self):
input = " \t Hello\n \tWorld"
expected = "\t Hello\n \tWorld"
self.failUnless Equal(expected, dedent(input, False))

if __name__ == '__main__':
unittest.main()
-tom!

--
Dec 23 '06 #9
Tom Plunket wrote:
Frederic Rentsch wrote:

>Following a call to dedent () it shouldn't be hard to translate leading
groups of so many spaces back to tabs.

Sure, but the point is more that I don't think it's valid to change to
tabs in the first place.

E.g.:

input = ' ' + '\t' + 'hello\n' +
'\t' + 'world'

output = textwrap.dedent (input)

will yield all of the leading whitespace stripped, which IMHO is a
violation of its stated function. In this case, nothing should be
stripped, because the leading whitespace in these two lines does not
/actually/ match. Sure, it visually matches, but that's not the point
(although I can understand that that's a point of contention in the
interpreter anyway, I would have no problem with it not accepting "1 tab
= 8 spaces" for indentation... But that's another holy war.

>If I understand your problem, you want to restore the dedented line to
its original composition if spaces and tabs are mixed and this doesn't
work because the information doesn't survive dedent ().

Sure, although would there be a case to be made to simply not strip the
tabs in the first place?

Like this, keeping current functionality and everything... (although I
would think if someone wanted tabs expanded, they'd call expandtabs on
the input before calling the function!):

def dedent(text, expand_tabs=Tru e):
"""dedent(t ext : string, expand_tabs : bool) -string

Remove any whitespace than can be uniformly removed from the left
of every line in `text`, optionally expanding tabs before altering
the text.

This can be used e.g. to make triple-quoted strings line up with
the left edge of screen/whatever, while still presenting it in the
source code in indented form.

For example:

def test():
# end first line with \ to avoid the empty line!
s = '''\
hello
\t world
'''
print repr(s) # prints ' hello\n \t world\n '
print repr(dedent(s)) # prints ' hello\n\t world\n'
"""
if expand_tabs:
text = text.expandtabs ()
lines = text.split('\n' )

margin = None
for line in lines:
if margin is None:
content = line.lstrip()
if not content:
continue
indent = len(line) - len(content)
margin = line[:indent]
elif not line.startswith (margin):
if len(line) < len(margin):
content = line.lstrip()
if not content:
continue
while not line.startswith (margin):
margin = margin[:-1]

if margin is not None and len(margin) 0:
margin = len(margin)
for i in range(len(lines )):
lines[i] = lines[i][margin:]

return '\n'.join(lines )

import unittest

class DedentTest(unit test.TestCase):
def testBasicWithSp aces(self):
input = "\n Hello\n World"
expected = "\nHello\n World"
self.failUnless Equal(expected, dedent(input))

def testBasicWithTa bLeadersSpacesI nside(self):
input = "\n\tHello\ n\t World"
expected = "\nHello\n World"
self.failUnless Equal(expected, dedent(input, False))

def testAllTabs(sel f):
input = "\t\tHello\n\tW orld"
expected = "\tHello\nWorld "
self.failUnless Equal(expected, dedent(input, False))

def testFirstLineNo tIndented(self) :
input = "Hello\n\tWorld "
expected = input
self.failUnless Equal(expected, dedent(input, False))

def testMixedTabsAn dSpaces(self):
input = " \t Hello\n \tWorld"
expected = "\t Hello\n \tWorld"
self.failUnless Equal(expected, dedent(input, False))

if __name__ == '__main__':
unittest.main()
-tom!

It this works, good for you. I can't say I understand your objective.
(You dedent common leading tabs, except if preceded by common leading
spaces (?)). Neither do I understand the existence of indentations made
up of tabs mixed with spaces, but that is another topic.
I have been wasting a lot of time with things of this nature coding
away before forming a clear conception in my mind of what my code was
supposed to accomplish. Sounds stupid. But many problems seem trivial
enough at first sight to create the illusion of perfect understanding.
The encounter with the devil in the details can be put off but not
avoided. Best to get it over with from the start and write an exhaustive
formal description of the problem. Follows an exhaustive formal
description of the rules for its solution. The rules can then be morphed
into code in a straightforward manner. In other words, coding should be
the translation of a logical system into a language a machine
understands. It should not be the construction of the logical system.
This, anyway, is the conclusion I have arrived at, to my advantage I
believe.

Frederic
Dec 25 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

699
33919
by: mike420 | last post by:
I think everyone who used Python will agree that its syntax is the best thing going for it. It is very readable and easy for everyone to learn. But, Python does not a have very good macro capabilities, unfortunately. I'd like to know if it may be possible to add a powerful macro system to Python, while keeping its amazing syntax, and if it could be possible to add Pythonistic syntax to Lisp or Scheme, while keeping all of the...
1
1553
by: Joshua Burvill | last post by:
Hello, How can I use the textwrap (new in 2.3) module if I have to use python 2.1? Rgds, Josh
1
3429
by: Dan Jacobson | last post by:
In wdg-html-reference/html40/block/pre.html there is no mention about how ASCII tabs (^I) are to be rendered. I suppose all bets are off? Wait, my docs go thru html-tidy first, and it says tab-size: number Sets the number of columns between successive tab stops. The default is 4. It is used to map tabs to spaces when reading files. Tidy never outputs files with tabs. However, in emacs, tab-width's value is 8. Solution:
17
2193
by: bearophileHUGS | last post by:
Hello, I know this topic was discussed a *lot* in the past, sorry if it bores you... >From the Daily Python-URL I've seen this interesting Floating Point Benchmark: http://www.fourmilab.ch/fourmilog/archives/2005-08/000567.html This is the source pack: http://www.fourmilab.ch/fbench/fbench.zip
1
3412
by: gjohannes | last post by:
Hi. I use Idle 1.1.1 on Python 2.4.1. The "Ctrl-" key bindings for indenting do not work on non-us keyboards where brackets are accessed by the "Alt Gr" key. The Tab key seem to work for indenting a selected textblock on my swedish keyboard, but Shift-tab does not dedent as you would have expected.
6
2042
by: Steven Bethard | last post by:
So I've recently been making pretty frequent use of textwrap.dedent() to allow me to use triple-quoted strings at indented levels of code without getting the extra spaces prefixed to each line. I discovered today that not only does textwrap.dedent() strip any leading spaces, but it also substitutes any internal tabs with spaces. For example:: py> def test(): .... x = ('abcd efgh\n' .... 'ijkl mnop\n') .... y =...
135
7456
by: Xah Lee | last post by:
Tabs versus Spaces in Source Code Xah Lee, 2006-05-13 In coding a computer program, there's often the choices of tabs or spaces for code indentation. There is a large amount of confusion about which is better. It has become what's known as “religious war” — a heated fight over trivia. In this essay, i like to explain what is the situation behind it, and which is proper.
3
1237
by: TP | last post by:
Hi everybody, Recently, I have tried to improve the look of the printed text in command line. For this, I was compelled to remove redundant spaces in strings, because in my scripts, often the strings are spreading on several lines. For example, "aaa bbb" had to be transformed in "aaa bbb". I have coded some simple functions to do that. Today, by examining Python documentation, I have found an interesting
0
8619
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, well explore What is ONU, What Is Router, ONU & Routers main usage, and What is the difference between ONU and Router. Lets take a closer look ! Part I. Meaning of...
0
9112
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8971
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
7651
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development projectplanning, coding, testing, and deploymentwithout human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5831
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4336
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4571
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2258
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
1970
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.