Don't bother with ord
Python already provide syntactic sugar for comparing characters in codepoint order, so ord(char) <= ord(s[index + 1]) can be shortened to char <= s[index+1]
Don't bother with the index
You only use index as a mean to look at the next character in s, you can dispense with it if you do
substr = s[0]
for char in s[1:]:
if substr[-1] <= char:
substr += char
else:
# Do your things
Don't use a string as an accumulator
Making substr a string is (probably) not the most efficient way to do it, as strings are immutable and you are constantly modifying it, better to make it a list of chars and join it only when needed
final_substr = []
substr = [s[0]]
for char in s[1:]:
if substr[-1] <= char:
substr.append(char)
else:
if len(substr) > len(final_substr):
final_substr = substr
substr = [char]
if len(substr) > len(final_substr):
final_substr = substr
final_substr = ''.join(final_substr)
Extra fanciness
in the code above, the string slicing s[1:] copies s, which might be an issue if you have to apply this procedure to a lot of very long strings. You can avoid that copy by using an iterator over s, changing the lines above to
s_iter = iter(s)
final_substr = []
substr = [next(s_iter)]
for char in s_iter:
# Nothing changes after this line
Or you could be more pedestrian and iterate over range(len(s)).
In the same vein, if you expect to have to deal with long substrings, you could transform everything to keep track of only the bounds of substr
final_bounds = [0, 1]
substr_bounds = [0, 1]
for i in range(1, len(s)):
if s[i-1] <= s[i]:
substr_bounds[1] += 1
else:
if final_bounds[1] - final_bounds[0] < substr_bounds[1] - substr_bounds[0]:
final_bounds = substr
substr_bounds = (i, i)
if final_bounds[1] - final_bounds[0] < substr_bounds[1] - substr_bounds[0]:
final_bounds = substr
final_substr = s[final_bounds[0]:final_bounds[1]]
This version should be the most efficient of all memory-wise. I do find it disgraceful, though.