[Feature Suggestion/Request] Python library #20
Replies: 14 comments
-
Looking into that is on my todo list. I'm thinking of at least allowing the effects to be imported and passed strings to run against. Something like the following:
The terminal output area state could be cleared or left with the results of the effect. That would allow the effects to run in the middle of other scripts without significantly disrupting the state of the terminal. In addition, I'm working on better documenting the API so others can more easily write effects. |
Beta Was this translation helpful? Give feedback.
-
Great to know it's on your TODO!
Yeah, this is actually along the lines of what I have in mind.
This though, isn't exactly or entirely all I have in mind. Yes, directly running and controlling animations is useful but only in synchronous CLI programs (i.e that perform operations one after another). For the animations to be more widely useful e.g in more complex CLIs, TUIs or even built upon in other libraries, a more flexible/concise API would be required. What I have in mind is more of modelling effects as iterators (since they're animations) which would yield the next frame of the animation on subsequent iterations. By "frame" I mean a unique single state of an animation at a specific time, which I want to believe already exists in the current design/implementation in some form. A frame can possibly be modeled as a string (or some other abstraction containing a string along with some other data). Yes, the effect classes and instances are still going to be useful. Currently, effect instances seem to be designed for single-use (i.e run the animation once and that's all). That, actually, is exactly what iterators are by design i.e single-use objects. Hence, I propose that effect classes should simply define the effect, it's properties, etc but that actually generation of the animation be devoted to iterator classes. More clearly, effect classes could implement The iterator classes on the other hand, should implement what is actually required to generate the animation and Effect classes would still implement the Also, concerning exporting the effects, I think exporting the effect classes themselves will do the job well.
That's definitely going to be handy. Talking about others writing effects (and in extension to what I've written earlier), I would suggest that effects have a unified/common API that models the core properties of and operations performed on and by any effect, which each individual effect can then extend if necessary. Looking into the current source, I see there's
Also, looking at NOTE: This is just a downpour of my raw thoughts (some on the fly). In case I made any typos or any aspect is unclear, feel free to bring it to my attention. Thanks for your audience. ❤️ |
Beta Was this translation helpful? Give feedback.
-
Well done @ChrisBuilds and @Navid-Means-Promise! Do you think this issue would be completely resolved once #5 is fully implemented across the code base? |
Beta Was this translation helpful? Give feedback.
-
Thank you @AnonymouX47 😉
However the PR @ChrisBuilds approved, will help to uses the TTE as a library but it don't cover none of your suggestions. |
Beta Was this translation helpful? Give feedback.
-
Noted. Thanks for the clarification. |
Beta Was this translation helpful? Give feedback.
-
A new branch has been published with a first draft implementation of library features. TTE as a library should provide two primary features:
In the spirit of limiting scope creep and keeping things simple, use cases beyond these two are unlikely to be supported. That being said, compelling cases with general applicability will be considered. All effects have been refactored into generator functions which yield frames as a string. Basic usage is as follows: from terminaltexteffects.effects import effect_rain
input_data = "Your String Here"
rain = effect_rain(input_data)
for frame in rain:
# do something with the frame string
... The Terminal class has been refactored to enable outputting the animation should the user of the library desire. Using Note: If the user prints anything else between calls to input_data = "Your String Here"
rain = effect_rain.RainEffect(input_data)
rain.terminal.prep_outputarea() # adds space for the effect and hides the cursor
for frame in rain:
rain.terminal.print(frame)
rain.terminal.restore_cursor() Configuration changes which were previously passed as arguments through the CLI are available through from terminaltexteffects.effects import effect_rain
from terminaltexteffects.utils.terminal import TerminalConfig
term_conf = TerminalConfig()
effect_conf = effect_rain.EffectConfig()
term_conf.no_wrap = True
term_conf.xterm_colors = True
effect_conf.rain_colors = ("ff0000", "00ff00")
effect_conf.movement_speed = (0.1, 0.9)
input_data = "Your String Here"
rain = effect_rain.RainEffect(input_data, effect_config=effect_conf, terminal_config=term_conf)
rain.terminal.prep_outputarea()
for frame in rain:
rain.terminal.print(frame)
rain.terminal.restore_cursor() Some effects may require longer build times. To enable the library user some control over when the effect is built, all effects implement a input_data = "Your String Here"
rain = effect_rain.RainEffect(input_data)
rain.build()
rain.terminal.prep_outputarea()
for frame in rain:
rain.terminal.print(frame)
rain.terminal.restore_cursor() Check out the branch and provide any comments/suggestions for improvements. GLHF. |
Beta Was this translation helpful? Give feedback.
-
This looks great and promising already. Well done and thank you for your hardwork. 🎉 Quick SuggestionJust one quick comment/suggestion while I'm yet to check/test it out.I think a method on the effect base class would be very appropriate to encapsulate: rain.terminal.prep_outputarea()
for frame in rain:
rain.terminal.print(frame)
rain.terminal.restore_cursor() as it seems to be a potential common pattern in code using the library. By the way, a If there's already such a method, please ignore this and forgive my ignorance. 😃 I'll check and test it out very soon and give my feedback. Thank you very much. |
Beta Was this translation helpful? Give feedback.
-
Aside these points (for now), I believe everything else is great including the format of the frames (though I might have something to note about the way SGR sequences are used but not in this issue). Side noteI'm not sure but I don't think this is related to the changes on the branch, but I guess it's worthy of note:I noticed there's an _animate_chars() method defined on every effect class I checked. Why not define this as an animate_chars(characters) function in the tte.base_character module and import it into the effect modules, instead of the repetition? The proposed function will accept, as an argument, an iterable of characters to be animated.
So sorry for the very long (finally done after hours 😩) feedback. 🥲 Thank you very much. 😃 |
Beta Was this translation helpful? Give feedback.
-
For what it's worth... I'm willing to submit PR(s) addressing any or all of the changes I suggested above, if it's okay by you. Thank you. |
Beta Was this translation helpful? Give feedback.
-
This was done for consistency assuming the user would import the effect and access the config within the effect namespace such as
Yeah, I'm not satisfied with the current implementation and will be addressing this in the next few days.
Your assessment is correct. Methods such as those do not need to be exposed. Some of them were refactored into
I noticed this but left the behavior in while testing ideas for the interface. As you've indicated, this will be fixed by refactoring iter as is the current plan.
Oops, haha. Unintended.
The You could argue the loop itself could be made a part of As always, thanks for your hard work. I appreciate the suggestions and will be implementing some version of them in the near future. Time is the primary challenge for me at the moment, but this whole endeavor is for fun/learning, so I don't mind handling the refactors myself, though it will take at least a few days. Stay tuned for updates to this branch. |
Beta Was this translation helpful? Give feedback.
-
It's a pleasure. 😃
Glad to hear that. 👍
Totally understandable. For the record, I'm in no rush. Currently, I don't even have any particular use case but since the moment I came across the project, I saw the potential it held and wanted to help drive it beyond being just a command-line utility. Well done. 👍 |
Beta Was this translation helpful? Give feedback.
-
I've had a few hours to work on this, here's an update. I have two goals, at this time, for the library refactor.
For the first goal, the current approach is the following: Effects now subclass two abstract classes found in
Here's an example using the RandomSequence effect: class RandomSequence(BaseEffect[EffectConfig]):
"""Prints the input data in a random sequence, one character at a time."""
_config_cls = EffectConfig
_iterator_cls = RandomSequenceIterator
def __init__(self, input_data: str) -> None:
super().__init__(input_data)
Here's an example using the RandomSequence effect: class RandomSequenceIterator(BaseEffectIterator[EffectConfig]):
def __init__(self, effect: "RandomSequence") -> None:
super().__init__(effect)
# add any other attributes
# add any other methods
def __next__(self) -> str:
if some_condition:
# do effect logic to progress the effect state
next_frame = self._terminal.get_formatted_output_string()
return next_frame
raise StopIteration For the second goal, keeping library usage simple, the current approach is the following: The effect and terminal configuration classes do not need to be imported or instantiated separate from the effect. That is handled by the from terminaltexteffects.effects import effect_random_sequence
effect = effect_random_sequence.RandomSequence(test_input)
effect.effect_config.speed = 0.1
effect.terminal_config.tab_width = 2
for frame in effect:
... The effect/terminal configuration can be changed at any time without impacting existing iterators. If the user needs multiple configurations, they can instantiate multiple effect objects. Finally, here is an example of the context manager handling terminal setup/teardown. from terminaltexteffects.effects import effect_random_sequence
effect = effect_random_sequence.RandomSequence(test_input)
with effect.terminal_output() as terminal:
for frame in effect:
terminal.print(frame) As a note, I will be making significant changes to the As always, I welcome suggestions and feedback as some of this is new territory for me. |
Beta Was this translation helpful? Give feedback.
-
The library refactor branch has been merged and published in version 0.8.0. I'm sure there are plenty of improvements to be made, but it's working well enough to start getting feedback. A few additions beyond my last message: The Terminal now supports custom dimensions and ignoring terminal device dimensions. For instances where you want to ignore terminal dimensions altogether, such as working with a TUI library or outputting in any other unpredictable method: effect.terminal_config.ignore_terminal_dimensions = True This will set the output area dimensions based solely off the input text. Nothing will be wrapped or cut off. For instances where you want to limit the output area to a specific size manually. effect.terminal_config.terminal_dimensions = (80, 24) # width, height If this value is set to the default I'm going to leave this issue open for feedback to keep everything organized in here until the library matures and more specific issue are being raised. |
Beta Was this translation helpful? Give feedback.
-
Interestingly, I somehow thought I had replied a long time ago but I was going through my notifiations today (after a really busy period) and realised I haven't. Well done and thank you very much for your work! 🙏 |
Beta Was this translation helpful? Give feedback.
-
First of all, nice work here. 😃
Are there currently any plans for this to be used as a library?
That is, in a way the text effects can be easily embedded into applications or even other libraries.
If there's any interest, I may have some ideas or even be able to help with API design or implementation (though the latter largely depends on my availability).
Thank you.
Beta Was this translation helpful? Give feedback.
All reactions