How can I change python behavior when a text doesn't fit in the screen and goes back to line?

Question:

My problem is a bit hard to explain, I made a program that align the list to the longest class name, and what we see in This picture is what my program shows me when I launch it : S37 and 38 are at the same place than classes names because python goes back to line once screen border is reached.

Now, this is what I would like to have. Obviously for this case I printed it with spaces to show what it should look like, but the program has to adapt to all screen size, so this method is not viable at all.
Is there any way to align all textes as they should be no matter what is the screen size ?

The exemple list i’m using (list[x][0] is the class name and list[x][1] is the class) :

[['2', ['bob', 'patrick', 'mike', 'jhamed', 'brook', 'gianni', 'espoir', 'igor', 'estère', 'charlotte', 'marie-charlotte', 'charlotte-marie', 'pénellope', 'cunégonde', 'félicie', "zo'", 'esmeralda', 'canada']], ['longclass', ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', 'S10', 'S11', 'S12', 'S13', 'S14', 'S15', 'S16', 'S17', 'S18', 'S19', 'S20', 'S21', 'S22', 'S23', 'S24', 'S25', 'S26', 'S27', 'S28', 'S29', 'S30', 'S31', 'S32', 'S33', 'S34', 'S35', 'S36', 'S37', 'S38']], ['test2', ['S1', 'S2', 'S3', 'S4', 'S6']], ['extremely long class name', ['s1', 's2', 's3', 's4']]]

The code I use to add spaces to align (used after a program that find the biggest class name) :

for j in range(len(List)) :
    var = List[j]
    for i in range(length - len(List[j])) : #"length" is the number of letters in the biggest class name, with "extremely long class name" : 25
        var = var + " "
    print(j,length,length - len(List[j]),var,exemple)
Asked By: the shadow

||

Answers:

Here is a solution:

import shutil
maxWidth = shutil.get_terminal_size()[0]
buf = ''
List = [['2', ['bob', 'patrick', 'mike', 'jhamed', 'brook', 'gianni', 'espoir', 'igor', 'estère', 'charlotte', 
               'marie-charlotte', 'charlotte-marie', 'pénellope', 'cunégonde', 'félicie', "zo'", 'esmeralda', 'canada']],
        ['longclass', ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', 'S10', 'S11', 'S12', 'S13', 'S14',
                       'S15', 'S16', 'S17', 'S18', 'S19', 'S20', 'S21', 'S22', 'S23', 'S24', 'S25', 'S26', 'S27', 'S28', 'S29', 'S30', 'S31', 'S32', 'S33', 'S34', 'S35', 'S36', 'S37', 'S38']],
        ['test2', ['S1', 'S2', 'S3', 'S4', 'S6']], 
        ['extremely long class name', ['s1', 's2', 's3', 's4']]
       ]
classnameMaxLen = len(max( List, key=lambda L: len(L[0]))[0]) # return longest classname length

def flushBuf():
  global buf
  print( buf)
  buf = ''

def addClassnameToBuf( txt):
  global buf
  if len(buf): # Something from previous class?
    flushBuf()
  buf += txt + ': ' + ' ' * (classnameMaxLen - len(txt))
  
def addNameToBuf( txt:str):
  global buf
  
  if len(buf) + len(txt) >= maxWidth:
    flushBuf()

  if len(buf) == 0: # No classname means it's a continuation line.
    buf += (' ' * (classnameMaxLen  + len( ': ')))
    
  buf += txt

# Print column titles (optional)
addClassnameToBuf( "Class")
addNameToBuf( "Names")
for klass in List:
  addClassnameToBuf( klass[0])
  for i,name in enumerate( klass[1]):
    addNameToBuf( name + (', ' if i+1 != len(klass[1]) else ''))
flushBuf() # final flush

And the result is:

Class:                     Names
2:                         bob, patrick, mike, jhamed, 
                           brook, gianni, espoir, igor, 
                           estère, charlotte, 
                           marie-charlotte, 
                           charlotte-marie, pénellope, 
                           cunégonde, félicie, zo', 
                           esmeralda, canada
longclass:                 S1, S2, S3, S4, S5, S6, S7, 
                           S8, S9, S10, S11, S12, S13, 
                           S14, S15, S16, S17, S18, S19, 
                           S20, S21, S22, S23, S24, S25, 
                           S26, S27, S28, S29, S30, S31, 
                           S32, S33, S34, S35, S36, S37, 
                           S38
test2:                     S1, S2, S3, S4, S6
extremely long class name: s1, s2, s3, s4

A more elegant solution would be possible using an object-oriented design.
If you need help, do not hesitate to ask.
Note: there is a superfluous apostrophe near "zo" name.

Answered By: user3435121

I played a bit with shutil and this is the version I managed to make.
Obviously @user3435121 ‘s script works too, and even a bit better because it does not cut in half students names. Thank you all for your help.

List = [['2', ['bob', 'patrick', 'mike', 'jhamed', 'brook', 'gianni', 'espoir', 'igor', 'estère', 'charlotte', 'marie-charlotte', 'charlotte-marie', 'pénellope', 'cunégonde', 'félicie', "zo'", 'esmeralda', 'canada']], ['longclass', ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7', 'S8', 'S9', 'S10', 'S11', 'S12', 'S13', 'S14', 'S15', 'S16', 'S17', 'S18', 'S19', 'S20', 'S21', 'S22', 'S23', 'S24', 'S25', 'S26', 'S27', 'S28', 'S29', 'S30', 'S31', 'S32', 'S33', 'S34', 'S35', 'S36', 'S37', 'S38']], ['test2', ['S1', 'S2', 'S3', 'S4', 'S6']], ['extremely long class name', ['s1', 's2', 's3', 's4']]]

import shutil

def findLongestClassName(List):
    longest = 0
    for i in range(len(List)):
        if len(List[i][0]) > longest :
            longest = len(List[i][0])
    return longest

def printClasses(List) :
    matrice = " : "
    longest = findLongestClassName(List)+len(matrice)
    screenx,screeny = shutil.get_terminal_size()
    lengthOfSingleLine = screenx-longest
    if longest >= screenx :
        print("too narrow window")
        return None

    for i in range(len(List)) :
        cleanClass = str(List[i][1]).replace("[", "").replace("]", "").replace("'", "")
        cleanClassList = list(cleanClass) #imossible to edit a str directly
        availableSpace = lengthOfSingleLine

        while len(cleanClassList) > availableSpace :

            if cleanClassList[availableSpace] == " " : #not necessary, it's just to make indent cleaner
                del cleanClassList[availableSpace]
            if cleanClassList[availableSpace] == "," and cleanClassList[availableSpace+1] == " " :
                del cleanClassList[availableSpace]
                del cleanClassList[availableSpace]

            cleanClassList[availableSpace] = " "*longest+cleanClassList[availableSpace]
            availableSpace += lengthOfSingleLine
            cleanClass = ""
            for j in cleanClassList:
                cleanClass += j
        print(List[i][0]+" "*(longest-len(matrice)-len(List[i][0]))+matrice+cleanClass)


while True :
    print(" - - - - - - - - - start - - - - - - - - - ")
    printClasses(List)
    input()

The result : result

Answered By: the shadow
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.