DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Start Coding With Google Cloud Workstations
  • Beyond ChatGPT, AI Reasoning 2.0: Engineering AI Models With Human-Like Reasoning
  • Why I Started Using Dependency Injection in Python
  • Reinforcement Learning for AI Agent Development: Implementing Multi-Agent Systems

Trending

  • Breaking Bottlenecks: Applying the Theory of Constraints to Software Development
  • Google Cloud Document AI Basics
  • Unlocking AI Coding Assistants Part 3: Generating Diagrams, Open API Specs, And Test Data
  • Integrating Security as Code: A Necessity for DevSecOps
  1. DZone
  2. Coding
  3. Languages
  4. Python curses, Part 1: Drawing With Text

Python curses, Part 1: Drawing With Text

Discover how to draw with text using the Python curses library. Learn setup, key considerations and how to create basic framework for your application.

By 
DZone Editorial user avatar
DZone Editorial
·
Apr. 21, 25 · Tutorial
Likes (0)
Comment
Save
Tweet
Share
1.6K Views

Join the DZone community and get the full member experience.

Join For Free

Most user interaction with Linux is done from afar via SSH connections and console applications. This, of course, is the continuing legacy of Linux’s “text only” roots, and many of these console applications tend to be “boring” workhorses which spit out line after line of output, with the occasional user input breaking up the monotony.

However, there is no reason console applications cannot be “spiced up” with windowed interfaces that feature colors, formatted text, and text placed — and updated‚ at various locations in a terminal window.

ncurses and curses Library in Python

ncurses is a Linux shared library that allows for programmatically updating a terminal screen without having to worry about the particulars of the terminal. It was originally developed for C/C++, but it has been ported to other programming languages, including Python. The name ncurses is short for “new curses” as this library emulates the original proprietary curses library that was featured in the Unix operating systems that preceded Linux. The ncurses library is also able to handle non-blocking keyboard input without root access.

The ncurses implementation in Python shares its name with the original Unix’s curses library. It is called the Python curses module.

The code examples in this article were run in the following environments:

  • Ubuntu 22.04 LTS with Python 3.10.4
  • Kali Linux 2022.2 with Python 3.10.4
  • Windows 10 Professional with Python 3.10.15

Some of these examples may not work with Windows. The demonstrations in this programming tutorial series — of which this is part one — also presume a basic working understanding of Python on the part of the reader.

What Are the Downsides of the curses Library in Python?

There is usually a steep learning curve associated with any software library that facilitates complex tasks, especially if it is built on top of a C-based library that is decades old. curses is no exception, but there are a few shortcuts that can help a beginner hit the ground running quickly. While it would be ideal to jump directly into a “Hello, world!”-style curses-enabled Python program, there are a few major quirks which should at least be briefly explained so that said “Hello, world!” program will stand an even remote chance of working.

Because it would be quite aggravating to not even be able to get a simple “Hello, world!” program working correctly, right? Right.

The biggest obstacles of working with the Python curses library tend to be:

  • Justifications
  • Missing libraries
  • Terminal compatibility
  • Error handling
  • Starting and ending ncurses
  • Computing horsepower

Why Use the Python curses Library?

One may ask “Why develop an application in this manner? Why not just develop a graphical application that runs over X11 and be done with it?”

The main argument against developing an X11-based application is that many Linux servers do not bother running with support for X11. Many sysadmins see no need to expend the resources needed to support X11. Good luck with trying to get them to make an exception for a single application!

Additionally, even when X11 is supported, X11 connectivity in Linux is very temperamental (and this is being generous). There are far too many circumstances beyond the control of a developer which can more easily break the functionality of graphical applications via X11 when compared to using the curses module. Additionally, it is much easier to adapt existing text-based Python applications to make use of the curses module as opposed to recoding them to make use of X11.

Missing Libraries in the Python curses Module

While it is not explicitly required that the underlying C-based ncurses library packages need to be installed in order for curses in Python to work correctly, it may be entirely possible that a particular Python implementation may “insist” that the ncurses library packages be installed. In Linux; this can be done by using the following commands:

Python
 
$ sudo apt-get install libncurses5-dev libncursesw5-dev       # ncurses development libraries
$ sudo apt-get install libncurses5                  # ncurses implementation library
$ sudo apt-get install ncurses-doc                  # ncurses documentation, manual pages 

Note: The apt-get command works with Debian-based Linux distributions such as Ubuntu and Kali. For other distributions, the commands yum or dnf may be more appropriate.

The last library, ncurses-doc, provides access to the manual pages for ncurses. These can be accessed via the man command:

Python
 
$ man ncurses

The curses module is nominally present in Python installations in Linux.

Meanwhile, as ncurses is historically a Linux or Unix offering, it is not “natively” present in Windows. The Python curses module will not work in Windows until the windows-curses module is installed. This can be done using the following command:

Python
 
C…> pip3 install windows-curses

This command gives the output:

Image showing the successful installation of the "windows-curses" module.

Terminal Compatibility and the Python curses Module

In Linux, the ncurses library is wholly integrated into — and dependent upon — the terminal emulator that is used to display the output of the program. As there are many different terminal emulators out there, there may be “trivial” incompatibilities which may prevent ncurses-based programs from working correctly. The same ncurses-based program may work on one terminal emulation setup in a given computer, but break in a different terminal emulation setup in the same computer. There is not really an easy way to fix this aside from going into all sorts of esoteric details about terminal emulation that would be well beyond the scope of this programming tutorial.

Unfortunately, curses-enabled Python programs may inherit these deficiencies.

The popular Windows SSH client Putty is known to have issues with ncurses-based programs. The following terminal emulation software was used for the programs shown in this tutorial:

Table showing programs that used terminal emulation software.

There are many terminal emulation tweaks that can be used to fix deficiencies in a given terminal emulation package, but the best course of action for a beginner with ncurses in general, or curses in Python in particular, is to simply use a terminal emulator that works correctly right out of the box. Fortunately, there are many freely available terminal emulation clients for Windows, MacOS, or whatever other operating environment is being used.

And one other thing about terminals: their size can be variable.

One final note here: in order to invoke Windows PowerShell, type “powershell” without the quotation marks into the Windows Search Bar (next to the Start button) and select “Windows Powershell” when it comes up in the “Best Match” section of the Start Window.

Error Handling the Python curses Library

While the Python curses module is certainly quite effective at returning exceptions when things do not work, it is usually not very forthcoming about why those errors occurred. For example, say a programmer tries to instantiate a Python curses window object with a size larger than the terminal window. This results in an exception, but there is no exception message indicating that this is what the error is. A programmer will have to become very creative with tracing code and debugging in order to effectively learn how to use the Python curses module.

Be aware that starting an ncurses-based program in a terminal window that is too small to accommodate the size of all the window objects is a very common error.

How to Start and End ncurses in Python

All ncurses-based programs, including curses-enabled Python programs, require a specific startup and shutdown procedure, even if there are exceptions in the code that result in the program quitting prematurely. If this startup and shutdown procedure is not followed, then the terminal window may not be usable for other commands once the program quits. The startup procedure initializes ncurses and changes the terminal settings so that output can be written to the screen using that object. When this happens, calls to print functions will not work. However, once the ncurses shutdown procedure is complete, calls to print functions will work as before.

Every curses-based Python program must follow the framework below in order to cleanly exit; note where the startup and shutdown procedures begin and end:

Python
 
# demo-skeleton.py

import curses
import sys

def main(argv):
  # BEGIN ncurses startup/initialization...
  # Initialize the curses object.
  stdscr = curses.initscr()

  # Do not echo keys back to the client.
  curses.noecho()

  # Non-blocking or cbreak mode... do not wait for Enter key to be pressed.
  curses.cbreak()

  # Turn off blinking cursor
  curses.curs_set(False)

  # Enable color if we can...
  if curses.has_colors():
    curses.start_color()

  # Optional - Enable the keypad. This also decodes multi-byte key sequences
  # stdscr.keypad(True)

  # END ncurses startup/initialization...

  caughtExceptions = ""
  try:
   # Meat of the program goes here.

   # Below is Python's no-op directive. This is needed because a try block
   # cannot be empty.
   pass 
  except Exception as err:
   # Just printing from here will not work, as the program is still set to
   # use ncurses.
   # print ("Some error [" + str(err) + "] occurred.")
   caughtExceptions = str(err)

  # BEGIN ncurses shutdown/deinitialization...
  # Turn off cbreak mode...
  curses.nocbreak()

  # Turn echo back on.
  curses.echo()

  # Restore cursor blinking.
  curses.curs_set(True)

  # Turn off the keypad...
  # stdscr.keypad(False)

  # Restore Terminal to original state.
  curses.endwin()

  # END ncurses shutdown/deinitialization...

  # Display Errors if any happened:
  if "" != caughtExceptions:
   print ("Got error(s) [" + caughtExceptions + "]")

if __name__ == "__main__":
  main(sys.argv[1:])

When the code is executed in the try block above, any error will allow for the ncurses deinitialization code to execute so that a clean exit will happen. Any messages from exceptions will be displayed after the terminal settings have been restored.

Computing Horsepower Considerations for Python curses

Python curses-enabled programs have the potential to use a tremendous amount of CPU. With this in mind, avoid using devices like the Raspberry Pi or other similar “low horsepower” computers to run the demonstrations shown in this tutorial — they just cannot handle the load.

Final Thoughts on Python curses Configuration and Setup

This first part in our programming tutorial series discussing how to draw with text using the Python curses library showed developers how to setup the curses library in Python, some things to consider with regards to working with curses, and how to start and end curses. We also learned how to create a basic skeleton framework for our curses-based Python applications.

In the next part of this series, we will create our first functioning ncurses and curses Python application and learn how to position text: "Python curses, Part 2: How to Create a Python curses-Enabled Application."

Python (language)

Opinions expressed by DZone contributors are their own.

Related

  • Start Coding With Google Cloud Workstations
  • Beyond ChatGPT, AI Reasoning 2.0: Engineering AI Models With Human-Like Reasoning
  • Why I Started Using Dependency Injection in Python
  • Reinforcement Learning for AI Agent Development: Implementing Multi-Agent Systems

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!