
Hi, some time ago, I proposed a string method "dedent" (which currently is in the textwrap module). The RFE is at http://python.org/sf/1237680. Any opinions? If I don't get positive comments, I'll reject it. Reinhold -- Mail address is perfectly valid!

On 9/14/05, Reinhold Birkenfeld <reinhold-birkenfeld-nospam@wolke7.net> wrote:
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Following Avi's suggestion, can I raise this thread up again? I think that Reinhold's .dedent() method can be a good idea after all. The idea is to add a method called "dedent" to strings. It would do exactly what the current textwrap.indent function does. The motivation is to be able to write multilined strings easily without damaging the visual indentation of the source code, like this: def foo(): msg = '''\ From: %s To: %s\r\n' Subject: Host failure report for %s Date: %s %s '''.dedent() % (fr, ', '.join(to), host, time.ctime(), err) Writing multilined strings without spaces in the beginning of lines makes functions harder to read, since although the Python parser is happy with it, it breaks the visual indentation. On 9/15/05, Guido van Rossum <guido@python.org> wrote:
I've looked at the textwrap.dedent() function, and it's really simple and well defined: Given a string s, take s.expandtabs().split('\n'). Take the minimal number of whitespace chars at the beginning of each line (not counting lines with nothing but whitespaces), and remove it from each line. This means that the Python source code is simple, and there would be no problems to write it in C. On 9/15/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
I think that the difference between "dedent" and "md5", "crc32" and such is the fact that making "dedent" a method helps writing code that is easier to read. Strings already have a lot of methods which don't make code clearer the way "dedent" will, such as center, capitalize, expandtabs, and many others. I think that given these, there's no reason not to add "dedent" as a string method. Noam

On 11/12/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
Sorry, I didn't mean to mislead. I wrote "easily" - I guess using the current textwrap.dedent isn't really hard, but still, writing: import textwrap ... r = some_func(textwrap.dedent('''\ line1 line2''')) Seems harder to me than simply r = some_func('''\ line1 line2'''.dedent()) This example brings up another reason why "dedent" us a method is a good idea: It is a common convention to indent things according to the last opening bracket. "dedent" as a function makes the indentation grow in at least 7 characters, and in 16 characters if you don't do "from textwrap import dedent". Another reason to make it a method is that I think it focuses attention at the string, which comes first, instead of at the "textwrap.dedent", which is only there to make the code look nicer. And, a last reason: making dedent a built-in method makes it a more "official" way of doing things, and I think that this way of writing a multilined string inside an indented block is really the best way to do it. Noam

Noam Raphael wrote:
I think a better argument for this is that dedenting a literal string is more of a syntactic operation than a functional one. You don't think "oh, I bet I'll need to do some dedenting on line 200 of this module, I better import textwrap". Instead you start writing a long string literal once you get to line 200. You can do it a few ways: some_func("line1\nline2") some_func("line1\n" "line2") some_func("""\ line1 line2""") # If nice whitespace would be pretty but not required: some_func(""" line1 line2""") I often do that last one with HTML and SQL. In practice textwrap.dedent() isn't one of the ways you are likely to write this statement. At least I've never done it that way (and I hit the issue often), and I don't think I've seen code that has used that in this circumstance. Additionally I don't think textwrapping has anything particular to do with dedenting, except perhaps that both functions were required when that module was added. I guess I just find the import cruft at the top of my files a little annoying, and managing them rather tedious, so saying that you should import textwrap because it makes a statement deep in the file look a little prettier is unrealistic. At the same time, the forms that don't use it are rather ugly or sloppy. -- Ian Bicking | ianb@colorstudy.com | http://blog.ianbicking.org

Ian Bicking wrote:
And regardless of the need to import, there's a feeling that it's something that ought to be done at compile time, or even parse time. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

James Y Knight wrote:
ITYM you mean "If only python were lisp". (macros, or even reader macros)
No, I mean it would be more satisfying if there were a syntax for expressing multiline string literals that didn't force it to be at the left margin. The lack of such in such an otherwise indentation-savvy language seems a wart. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

Greg Ewing <greg.ewing@canterbury.ac.nz> writes:
Wasn't there a PEP about this? Yes, 295. But that was rejected, I presume[*] because it proposed changing all multi-string literals, a plainly doomed idea (well, it would make *me* squeal, anyway). Cheers, mwh (who finds the whole issue rather hard to care about) [*] The reason for rejection isn't in the PEP, grumble. -- I would hereby duly point you at the website for the current pedal powered submarine world underwater speed record, except I've lost the URL. -- Callas, cam.misc

It's a common convention, but a rather ugly one. It makes harder breaking lines at 78-80 chars, and using long enough identifiers. I find it more useful to go straight to the next line, indenting the usual four spaces (and also separating nested stuff): r = some_func( textwrap.dedent( '''\ line1 line2''')) This style uses up more vertical space, but I find it also gives code a clearer overall shape. -- Nicola Larosa - nico@tekNico.net Use of threads can be very deceptive. [...] in almost all cases they also make debugging, testing, and maintenance vastly more difficult and sometimes impossible. http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#why

Raymond Hettinger wrote:
In textwrap module this function placed in section "Loosely (!) related functionality". When Python beginner try to find "Pythonic" way for dealing with dedenting (And she know, in Python "there should be one -- and preferably only one -- obvious way to do it"), it is very unlikely that she think "Which module may contain standard string dedenting? Yes, of course textwrap! I'm sure I'll find necessary function there!"
I think, dedenting must be classified as "generic string manipulations". The need in string dedenting results from meaningful indentation and widespread use of text editors with folding support. Multiline strings without leading whitespaces breaks correct folding in some editors. Best regards, Alexander mailto:kozlovsky@mail.spbnit.ru

Noam Raphael wrote:
You are missing a point here: string methods were introduced to make switching from plain 8-bit strings to Unicode easier. As such they are only needed in cases where an algorithm has to work on the resp. internals differently or where direct access to the internals makes a huge difference in terms of performance. In your use case, the algorithm is independent of the data type interals and can be defined solely by using existing string method APIs.
This is really a minor compiler/parser issue and not one which warrants adding another string method. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Nov 13 2005)
2005-10-17: Released mxODBC.Zope.DA 1.0.9 http://zope.egenix.com/ ::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::

You are missing a point here: string methods were introduced to make switching from plain 8-bit strings to Unicode easier.
Is it the only purpose ? I agree with the OP that using string methods is much nicer and more convenient than having to import separate modules. Especially, it is nice to just type help(str) in the interactive prompt and get the list of supported methods. Also, these methods are living in the namespace of the supported objects. It feels very natural, and goes hand in hand with Python's object-oriented nature. (just my 2 cents - I am not arguing for or against the specific case of dedent, by the way) Regards Antoine.

On Sunday 2005-11-13 17:43, Marc-Andre Lemburg wrote: [Noam Raphael:]
The idea is to add a method called "dedent" to strings. It would do exactly what the current textwrap.indent function does.
[Marc-Andre:]
In a language that generally pays as much attention to practical usability as Python, it seems a pity to say (as you seem to be implying) that whether something is a string method or a function in (say) the "textwrap" module should be determined by internal implementation details.
Adding another string method seems easier, and a smaller change, than altering the compiler or parser. What's your point here? I think I must be missing something. -- g

Gareth McCaughan wrote:
We have to draw a line somewhere - otherwise you could just as well add all functions that accept single string arguments as methods to the basestring sub-classes.
The point is that the presented use case does not originate in a common need (to dedent strings), but from a desire to write Python code with embedded indented triple-quoted strings which lies in the scope of the parser, not that of string objects. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Nov 14 2005)
2005-10-17: Released mxODBC.Zope.DA 1.0.9 http://zope.egenix.com/ ::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::

On 11/14/05, M.-A. Lemburg <mal@egenix.com> wrote:
Please read my first post in this thread - I think there's more reason for 'dedent' to be a string method than there is, for example, for 'expandtabs', since it allows you to write clearer code.
That's a theoretical argument. In practice, if you do it in the parser, you have two options: 1. Automatically dedent all strings. 2. Add a 'd' or some other letter before the string. Option 1 breaks backwards compatibility, and makes the parser do unexpected things. Option 2 adds another string-prefix letter, which is confusing, and it will also be hard to find out what that letter means. On the other hand, adding ".dedent()" at the end is very clear, and is just as easy. Now, about performance, please see the message I'll post in a few minutes... Noam

Noam Raphael wrote:
so is putting the string constant in a global variable, outside the scope you're in, like you'd do with any other constant. (how about a new rule: you cannot post to a zombie thread on python- dev unless they've fixed/reviewed/applied or otherwise processed at least one tracker item earlier the same day. there are hundreds of items on the bugs and patches trackers that could need some loving care) </F>

On 11/14/05, Fredrik Lundh <fredrik@pythonware.com> wrote:
so is putting the string constant in a global variable, outside the scope you're in, like you'd do with any other constant.
Usually when I use a constant a single time, I write it where I use it, and don't give it a name. I don't do: messagea = "The value of A is " ... (a long class definition) print messagea, A This is what I mean when I say "constant" - a value which is known when I write the code, not necessarily an arbitrary value that may change, so I write it at the beginning of the program for others to know it's there. There's no reason why multilined strings that are used only once should be defined at the beginning of a program (think about a simple CGI script, which prints HTML parts in a function.)
I posted to this thread because it was relevant to a new post about dedenting strings. Anyway, I looked at bug 1356720 (Ctrl+C for copy does not work when caps-lock is on), and posted there a very simple patch which will most probably solve the problem. I also looked at bug 1337987 (IDLE, F5 and wrong external file content. (on error!)). One problem it raises is that IDLE doesn't have a "revert" command and that it doesn't notice if the file was changed outside of IDLE. I am planning to fix it. The other problem that is reported in that bug is that exceptions show misleading code lines when the source file was changed but wasn't loaded into Python. Perhaps in compiled code, not only the file name should be written but also its modification time? This way, when tracebacks print lines of changed files, they can warn if the line might not be the right line. Noam

Noam Raphael wrote:
I find that simple CGI scripts are precisely the example *for* putting multi-line string literals at the beginning of a file. There are multiple styles for writing such things: 1. Put headers and trailers into separate strings. This tends to become tedious to maintain, since you always have to find the matching string (e.g. if you add an opening tag in the header, you have to put the closing tag in the trailer). 2. Use interpolation (e.g. % substitution), and put the strings into the code. This works fine for single line strings. For multi-line strings, the HTML code tends to clutter the view of the algorithm, whether it is indented or not. Functions should fit on a single screen of text, and adding multiline text into functions tends to break this requirement. 3. Use interpolation, and put the templates at the beginning. This makes the templates easy to inspect, and makes it easy to follow the code later in the file. It is the style I use and recommend. Of course, it may occasionally become necessary to have a few-lines string literally in a function; in most cases, indenting it along with the rest of the function is fine, as HTML can stand extra spaces with no problems. Regards, Martin

Thanks for your examples. I understand tham sometimes it's a good idea not to write the HTML inside the function (although it may be nice to sometimes write it just before the function - and if it's a method, then we get the same indentation problem.) However, as you said, sometimes it is desired to write multilined strings inside functions. You think it's ok to add white spaces to the HTML code, I personally prefer not add varying indentation to my output according to the level of indentation the code that generated it. I just wanted to add another use case: long messages. Consider those lines from idlelib/run.py:133 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\ "to your personal firewall configuration. It is safe to "\ "allow this internal connection because no data is visible on "\ "external ports." % address tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root) and from idlelib/PyShell.py:734: def display_port_binding_error(self): tkMessageBox.showerror( "Port Binding Error", "IDLE can't bind TCP/IP port 8833, which is necessary to " "communicate with its Python execution server. Either " "no networking is installed on this computer or another " "process (another IDLE?) is using the port. Run IDLE with the -n " "command line switch to start without a subprocess and refer to " "Help/IDLE Help 'Running without a subprocess' for further " "details.", master=self.tkconsole.text) I know, of course, that it could be written using textwrap.dedent, but I think that not having to load a module will encourage the use of dedent; if I have to load a module, I might say, "oh, I can live with all those marks around the text, there's no need for another module", and then, any time I want to change that message, I have a lot of editing work to do. Noam

On 11/18/05, "Martin v. Löwis" <martin@v.loewis.de> wrote:
Only if you didn't include newline escapes, e.g.:: msg = textwrap.dedent('''\ IDLE's subprocess can't connect to %s:%d. This may be due \ to your personal firewall configuration. It is safe to \ allow this internal connection because no data is visible on \ external ports.''' % address) STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy

Just two additional notes: On 9/15/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
It may seem like the 'dedent' code would have to be written a lot of times, but I've checked the examples. It may be needed to write different versions for 'str' and for 'unicode', but these are going to be unified. In UserString you'll have to add exactly one line: def dedent(self): return self.data.dedent() I've just taken the line created for 'isalpha' and replaced 'isalpha' with 'dedent'. So in the long run, there will be exactly one implementation of 'dedent' in the Python code. (I don't know of any other objects which try to provide the full string interface.) Another reason for prefering a 'dedent' method over a 'dedent' function in some module, is that it allows sometime in the future to add an optimization to the compiler, so that it will dedent the string in compile time (this can't work for a function, since the function is found in run time). This will solve the performance problem completely, so that there will be an easy way to write multilined strings which do not interfere with the visual structure of the code, without the need to worry about performance. I'm not saying that this optimization has to be done now, just that 'dedent' as a method makes it possible, which adds to the other arguments for making it a method. Noam

-1 Let it continue to live in textwrap where the existing pure python code adequately serves all string-like objects. It's not worth losing the duck typing by attaching new methods to str, unicode, UserString, and everything else aspiring to be string-like. String methods should be limited to generic string manipulations. String applications should be in other namespaces. That is why we don't have str.md5(), str.crc32(), str.ziplib(), etc. Also, I don't want to encourage dedenting as a way of life --- programs using it often are likely to be doing things the hard way. Raymond

On 9/14/05, Reinhold Birkenfeld <reinhold-birkenfeld-nospam@wolke7.net> wrote:
-- --Guido van Rossum (home page: http://www.python.org/~guido/)

Following Avi's suggestion, can I raise this thread up again? I think that Reinhold's .dedent() method can be a good idea after all. The idea is to add a method called "dedent" to strings. It would do exactly what the current textwrap.indent function does. The motivation is to be able to write multilined strings easily without damaging the visual indentation of the source code, like this: def foo(): msg = '''\ From: %s To: %s\r\n' Subject: Host failure report for %s Date: %s %s '''.dedent() % (fr, ', '.join(to), host, time.ctime(), err) Writing multilined strings without spaces in the beginning of lines makes functions harder to read, since although the Python parser is happy with it, it breaks the visual indentation. On 9/15/05, Guido van Rossum <guido@python.org> wrote:
I've looked at the textwrap.dedent() function, and it's really simple and well defined: Given a string s, take s.expandtabs().split('\n'). Take the minimal number of whitespace chars at the beginning of each line (not counting lines with nothing but whitespaces), and remove it from each line. This means that the Python source code is simple, and there would be no problems to write it in C. On 9/15/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
I think that the difference between "dedent" and "md5", "crc32" and such is the fact that making "dedent" a method helps writing code that is easier to read. Strings already have a lot of methods which don't make code clearer the way "dedent" will, such as center, capitalize, expandtabs, and many others. I think that given these, there's no reason not to add "dedent" as a string method. Noam

On 11/12/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
Sorry, I didn't mean to mislead. I wrote "easily" - I guess using the current textwrap.dedent isn't really hard, but still, writing: import textwrap ... r = some_func(textwrap.dedent('''\ line1 line2''')) Seems harder to me than simply r = some_func('''\ line1 line2'''.dedent()) This example brings up another reason why "dedent" us a method is a good idea: It is a common convention to indent things according to the last opening bracket. "dedent" as a function makes the indentation grow in at least 7 characters, and in 16 characters if you don't do "from textwrap import dedent". Another reason to make it a method is that I think it focuses attention at the string, which comes first, instead of at the "textwrap.dedent", which is only there to make the code look nicer. And, a last reason: making dedent a built-in method makes it a more "official" way of doing things, and I think that this way of writing a multilined string inside an indented block is really the best way to do it. Noam

Noam Raphael wrote:
I think a better argument for this is that dedenting a literal string is more of a syntactic operation than a functional one. You don't think "oh, I bet I'll need to do some dedenting on line 200 of this module, I better import textwrap". Instead you start writing a long string literal once you get to line 200. You can do it a few ways: some_func("line1\nline2") some_func("line1\n" "line2") some_func("""\ line1 line2""") # If nice whitespace would be pretty but not required: some_func(""" line1 line2""") I often do that last one with HTML and SQL. In practice textwrap.dedent() isn't one of the ways you are likely to write this statement. At least I've never done it that way (and I hit the issue often), and I don't think I've seen code that has used that in this circumstance. Additionally I don't think textwrapping has anything particular to do with dedenting, except perhaps that both functions were required when that module was added. I guess I just find the import cruft at the top of my files a little annoying, and managing them rather tedious, so saying that you should import textwrap because it makes a statement deep in the file look a little prettier is unrealistic. At the same time, the forms that don't use it are rather ugly or sloppy. -- Ian Bicking | ianb@colorstudy.com | http://blog.ianbicking.org

Ian Bicking wrote:
And regardless of the need to import, there's a feeling that it's something that ought to be done at compile time, or even parse time. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

James Y Knight wrote:
ITYM you mean "If only python were lisp". (macros, or even reader macros)
No, I mean it would be more satisfying if there were a syntax for expressing multiline string literals that didn't force it to be at the left margin. The lack of such in such an otherwise indentation-savvy language seems a wart. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+

Greg Ewing <greg.ewing@canterbury.ac.nz> writes:
Wasn't there a PEP about this? Yes, 295. But that was rejected, I presume[*] because it proposed changing all multi-string literals, a plainly doomed idea (well, it would make *me* squeal, anyway). Cheers, mwh (who finds the whole issue rather hard to care about) [*] The reason for rejection isn't in the PEP, grumble. -- I would hereby duly point you at the website for the current pedal powered submarine world underwater speed record, except I've lost the URL. -- Callas, cam.misc

It's a common convention, but a rather ugly one. It makes harder breaking lines at 78-80 chars, and using long enough identifiers. I find it more useful to go straight to the next line, indenting the usual four spaces (and also separating nested stuff): r = some_func( textwrap.dedent( '''\ line1 line2''')) This style uses up more vertical space, but I find it also gives code a clearer overall shape. -- Nicola Larosa - nico@tekNico.net Use of threads can be very deceptive. [...] in almost all cases they also make debugging, testing, and maintenance vastly more difficult and sometimes impossible. http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html#why

Raymond Hettinger wrote:
In textwrap module this function placed in section "Loosely (!) related functionality". When Python beginner try to find "Pythonic" way for dealing with dedenting (And she know, in Python "there should be one -- and preferably only one -- obvious way to do it"), it is very unlikely that she think "Which module may contain standard string dedenting? Yes, of course textwrap! I'm sure I'll find necessary function there!"
I think, dedenting must be classified as "generic string manipulations". The need in string dedenting results from meaningful indentation and widespread use of text editors with folding support. Multiline strings without leading whitespaces breaks correct folding in some editors. Best regards, Alexander mailto:kozlovsky@mail.spbnit.ru

Noam Raphael wrote:
You are missing a point here: string methods were introduced to make switching from plain 8-bit strings to Unicode easier. As such they are only needed in cases where an algorithm has to work on the resp. internals differently or where direct access to the internals makes a huge difference in terms of performance. In your use case, the algorithm is independent of the data type interals and can be defined solely by using existing string method APIs.
This is really a minor compiler/parser issue and not one which warrants adding another string method. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Nov 13 2005)
2005-10-17: Released mxODBC.Zope.DA 1.0.9 http://zope.egenix.com/ ::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::

You are missing a point here: string methods were introduced to make switching from plain 8-bit strings to Unicode easier.
Is it the only purpose ? I agree with the OP that using string methods is much nicer and more convenient than having to import separate modules. Especially, it is nice to just type help(str) in the interactive prompt and get the list of supported methods. Also, these methods are living in the namespace of the supported objects. It feels very natural, and goes hand in hand with Python's object-oriented nature. (just my 2 cents - I am not arguing for or against the specific case of dedent, by the way) Regards Antoine.

On Sunday 2005-11-13 17:43, Marc-Andre Lemburg wrote: [Noam Raphael:]
The idea is to add a method called "dedent" to strings. It would do exactly what the current textwrap.indent function does.
[Marc-Andre:]
In a language that generally pays as much attention to practical usability as Python, it seems a pity to say (as you seem to be implying) that whether something is a string method or a function in (say) the "textwrap" module should be determined by internal implementation details.
Adding another string method seems easier, and a smaller change, than altering the compiler or parser. What's your point here? I think I must be missing something. -- g

Gareth McCaughan wrote:
We have to draw a line somewhere - otherwise you could just as well add all functions that accept single string arguments as methods to the basestring sub-classes.
The point is that the presented use case does not originate in a common need (to dedent strings), but from a desire to write Python code with embedded indented triple-quoted strings which lies in the scope of the parser, not that of string objects. -- Marc-Andre Lemburg eGenix.com Professional Python Services directly from the Source (#1, Nov 14 2005)
2005-10-17: Released mxODBC.Zope.DA 1.0.9 http://zope.egenix.com/ ::: Try mxODBC.Zope.DA for Windows,Linux,Solaris,FreeBSD for free ! ::::

On 11/14/05, M.-A. Lemburg <mal@egenix.com> wrote:
Please read my first post in this thread - I think there's more reason for 'dedent' to be a string method than there is, for example, for 'expandtabs', since it allows you to write clearer code.
That's a theoretical argument. In practice, if you do it in the parser, you have two options: 1. Automatically dedent all strings. 2. Add a 'd' or some other letter before the string. Option 1 breaks backwards compatibility, and makes the parser do unexpected things. Option 2 adds another string-prefix letter, which is confusing, and it will also be hard to find out what that letter means. On the other hand, adding ".dedent()" at the end is very clear, and is just as easy. Now, about performance, please see the message I'll post in a few minutes... Noam

Noam Raphael wrote:
so is putting the string constant in a global variable, outside the scope you're in, like you'd do with any other constant. (how about a new rule: you cannot post to a zombie thread on python- dev unless they've fixed/reviewed/applied or otherwise processed at least one tracker item earlier the same day. there are hundreds of items on the bugs and patches trackers that could need some loving care) </F>

On 11/14/05, Fredrik Lundh <fredrik@pythonware.com> wrote:
so is putting the string constant in a global variable, outside the scope you're in, like you'd do with any other constant.
Usually when I use a constant a single time, I write it where I use it, and don't give it a name. I don't do: messagea = "The value of A is " ... (a long class definition) print messagea, A This is what I mean when I say "constant" - a value which is known when I write the code, not necessarily an arbitrary value that may change, so I write it at the beginning of the program for others to know it's there. There's no reason why multilined strings that are used only once should be defined at the beginning of a program (think about a simple CGI script, which prints HTML parts in a function.)
I posted to this thread because it was relevant to a new post about dedenting strings. Anyway, I looked at bug 1356720 (Ctrl+C for copy does not work when caps-lock is on), and posted there a very simple patch which will most probably solve the problem. I also looked at bug 1337987 (IDLE, F5 and wrong external file content. (on error!)). One problem it raises is that IDLE doesn't have a "revert" command and that it doesn't notice if the file was changed outside of IDLE. I am planning to fix it. The other problem that is reported in that bug is that exceptions show misleading code lines when the source file was changed but wasn't loaded into Python. Perhaps in compiled code, not only the file name should be written but also its modification time? This way, when tracebacks print lines of changed files, they can warn if the line might not be the right line. Noam

Noam Raphael wrote:
I find that simple CGI scripts are precisely the example *for* putting multi-line string literals at the beginning of a file. There are multiple styles for writing such things: 1. Put headers and trailers into separate strings. This tends to become tedious to maintain, since you always have to find the matching string (e.g. if you add an opening tag in the header, you have to put the closing tag in the trailer). 2. Use interpolation (e.g. % substitution), and put the strings into the code. This works fine for single line strings. For multi-line strings, the HTML code tends to clutter the view of the algorithm, whether it is indented or not. Functions should fit on a single screen of text, and adding multiline text into functions tends to break this requirement. 3. Use interpolation, and put the templates at the beginning. This makes the templates easy to inspect, and makes it easy to follow the code later in the file. It is the style I use and recommend. Of course, it may occasionally become necessary to have a few-lines string literally in a function; in most cases, indenting it along with the rest of the function is fine, as HTML can stand extra spaces with no problems. Regards, Martin

Thanks for your examples. I understand tham sometimes it's a good idea not to write the HTML inside the function (although it may be nice to sometimes write it just before the function - and if it's a method, then we get the same indentation problem.) However, as you said, sometimes it is desired to write multilined strings inside functions. You think it's ok to add white spaces to the HTML code, I personally prefer not add varying indentation to my output according to the level of indentation the code that generated it. I just wanted to add another use case: long messages. Consider those lines from idlelib/run.py:133 msg = "IDLE's subprocess can't connect to %s:%d. This may be due "\ "to your personal firewall configuration. It is safe to "\ "allow this internal connection because no data is visible on "\ "external ports." % address tkMessageBox.showerror("IDLE Subprocess Error", msg, parent=root) and from idlelib/PyShell.py:734: def display_port_binding_error(self): tkMessageBox.showerror( "Port Binding Error", "IDLE can't bind TCP/IP port 8833, which is necessary to " "communicate with its Python execution server. Either " "no networking is installed on this computer or another " "process (another IDLE?) is using the port. Run IDLE with the -n " "command line switch to start without a subprocess and refer to " "Help/IDLE Help 'Running without a subprocess' for further " "details.", master=self.tkconsole.text) I know, of course, that it could be written using textwrap.dedent, but I think that not having to load a module will encourage the use of dedent; if I have to load a module, I might say, "oh, I can live with all those marks around the text, there's no need for another module", and then, any time I want to change that message, I have a lot of editing work to do. Noam

On 11/18/05, "Martin v. Löwis" <martin@v.loewis.de> wrote:
Only if you didn't include newline escapes, e.g.:: msg = textwrap.dedent('''\ IDLE's subprocess can't connect to %s:%d. This may be due \ to your personal firewall configuration. It is safe to \ allow this internal connection because no data is visible on \ external ports.''' % address) STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy

Just two additional notes: On 9/15/05, Raymond Hettinger <raymond.hettinger@verizon.net> wrote:
It may seem like the 'dedent' code would have to be written a lot of times, but I've checked the examples. It may be needed to write different versions for 'str' and for 'unicode', but these are going to be unified. In UserString you'll have to add exactly one line: def dedent(self): return self.data.dedent() I've just taken the line created for 'isalpha' and replaced 'isalpha' with 'dedent'. So in the long run, there will be exactly one implementation of 'dedent' in the Python code. (I don't know of any other objects which try to provide the full string interface.) Another reason for prefering a 'dedent' method over a 'dedent' function in some module, is that it allows sometime in the future to add an optimization to the compiler, so that it will dedent the string in compile time (this can't work for a function, since the function is found in run time). This will solve the performance problem completely, so that there will be an easy way to write multilined strings which do not interfere with the visual structure of the code, without the need to worry about performance. I'm not saying that this optimization has to be done now, just that 'dedent' as a method makes it possible, which adds to the other arguments for making it a method. Noam

-1 Let it continue to live in textwrap where the existing pure python code adequately serves all string-like objects. It's not worth losing the duck typing by attaching new methods to str, unicode, UserString, and everything else aspiring to be string-like. String methods should be limited to generic string manipulations. String applications should be in other namespaces. That is why we don't have str.md5(), str.crc32(), str.ziplib(), etc. Also, I don't want to encourage dedenting as a way of life --- programs using it often are likely to be doing things the hard way. Raymond
participants (16)
-
"Martin v. Löwis"
-
Alexander Kozlovsky
-
Antoine Pitrou
-
Fredrik Lundh
-
Gareth McCaughan
-
Greg Ewing
-
Guido van Rossum
-
Ian Bicking
-
James Y Knight
-
M.-A. Lemburg
-
Michael Hudson
-
Nicola Larosa
-
Noam Raphael
-
Raymond Hettinger
-
Reinhold Birkenfeld
-
Steven Bethard