Thursday, September 30, 2021

Python⇒Speed: Building Docker images on GitLab CI: Docker-in-Docker and Podman

If you’re using GitLab CI to build your software, you might also want to use it to build Docker images of your application. This can be a little tricky, because by default GitLab CI runs jobs inside Docker containers.

The standard technique for getting around this problem is using Docker-in-Docker, but you can also use a simpler technique by using Podman, the reimplemented version of Docker. Let’s see why and how.

Read more...

from Planet Python
via read more

Mike Driscoll: Python 101 – How to Work with a Database Using sqlite3

Software developers have to work with data. More often than not, the data that you work with will need to be available to multiple developers as well as multiple users at once. The typical solution for this type of situation is to use a database. Databases hold data in a tabular format, which means that they have labeled columns and rows of data.

Most database software requires you to install complex software on your local machine or on a server you have access to. Popular database software includes Microsoft SQL Server, PostgreSQL, and MySQL, among others. For the purposes of this article, you will focus on a very simple one known as SQLite. The reason you will use SQLite is that it is a file-based database system that is included with Python. You won’t need to do any configuration or additional installation. This allows you to focus on the essentials of what a database is and how it functions, while avoiding the danger of getting lost in installation and setup details.

In this article, you will learn about the following:

  • Creating a SQLite Database
  • Adding Data to Your Database
  • Searching Your Database
  • Editing Data in Your Database
  • Deleting Data From Your Database

Let’s start learning about how to use Python with a database now!

Creating a SQLite Database

There are 3rd party SQL connector packages to help you connect your Python code to all major databases. The Python standard library already comes with a sqlite3 library built-in, which is what you will be using. This means that you won’t have to install anything extra in order to work through this article. You can read the documentation for the sqlite3 library here:

To start working with a database, you need to either connect to a pre-existing one or create a new one. For the purposes of this article, you will create a database. However, you will learn enough in this article to also load and interact with a pre-existing database if you want to.

SQLite supports the following types of data:

  • NULL
  • INTEGER
  • REAL
  • TEXT
  • BLOB

These are the data types that you can store in this type of database. If you want to read more about how Python data types translate to SQLite data types and vice-versa, see the following link:

Now it is time for you to create a database! Here is how you would create a SQLite database with Python:

import sqlite3

sqlite3.connect("library.db")

First, you import sqlite3 and then you use the connect() function, which takes the path to the database file as an argument. If the file does not exist, the sqlite3 module will create an empty database. Once the database file has been created, you need to add a table to be able to work with it. The basic SQL command you use for doing this is as follows:

CREATE TABLE table_name
(column_one TEXT, column_two TEXT, column_three TEXT)

Keywords in SQL are case-insensitive — so CREATE == Create == create. Identifiers, however, might be case-sensitive — it depends on the SQL engine being used and possibly what configuration settings are being used by that engine or by the database. If using a preexisting database, either check its documentation or just use the same case as it uses for table and field names.

You will be following the convention of KEYWORDS in UPPER-case, and identifiers in Mixed- or lower-case.

The CREATE TABLE command will create a table using the name specified. You follow that command with the name of each column as well as the column type. Columns can also be thought of as fields and column types as field types. The SQL code snippet above creates a three-column table where all the columns contain text. If you call this command and the table already exists in the database, you will receive an error.

You can create as many tables as the database allows. The number of rows and columns may have a limit from the database software, but most of the time you won’t run into this limit.

If you combine the information you learned in the last two examples, you can create a database for storing information about books. Create a new file named create_database.py and enter the following code:

# create_database.py

import sqlite3

conn = sqlite3.connect("library.db")

cursor = conn.cursor()

# create a table
cursor.execute("""CREATE TABLE books
                  (title TEXT, author TEXT, release_date TEXT,
                   publisher TEXT, book_type TEXT)
               """)

To work with a SQLite database, you need to connect() to it and then create a cursor() object from that connection. The cursor is what you use to send SQL commands to your database via its execute() function. The last line of code above will use the SQL syntax you saw earlier to create a books table with five fields:

  • title – The title of the book as text
  • author – The author of the book as text
  • release_date – The date the book was released as text
  • publisher – The publisher of the book as text
  • book_type – The type of book (print, epub, PDF, etc)

Now you have a database that you can use, but it has no data. You will discover how to add data to your table in the next section!

Adding Data to Your Database

Adding data to a database is done using the INSERT INTO SQL commands. You use this command in combination with the name of the table that you wish to insert data into. This process will become clearer by looking at some code, so go ahead and create a file named add_data.py. Then add this code to it:

# add_data.py

import sqlite3

conn = sqlite3.connect("library.db")
cursor = conn.cursor()

# insert a record into the books table in the library database
cursor.execute("""INSERT INTO books
                  VALUES ('Python 101', 'Mike Driscoll', '9/01/2020',
                          'Mouse Vs Python', 'epub')"""
               )

# save data
conn.commit()

# insert multiple records using the more secure "?" method
books = [('Python Interviews', 'Mike Driscoll',
          '2/1/2018', 'Packt Publishing', 'softcover'),
         ('Automate the Boring Stuff with Python',
          'Al Sweigart', '', 'No Starch Press', 'PDF'),
         ('The Well-Grounded Python Developer',
          'Doug Farrell', '2020', 'Manning', 'Kindle')]
cursor.executemany("INSERT INTO books VALUES (?,?,?,?,?)", books)
conn.commit()

The first six lines show how to connect to the database and create the cursor as before. Then you use execute() to call INSERT INTO and pass it a series of five VALUES. To save that record to the database table, you need to call commit().

The last few lines of code show how to commit multiple records to the database at once using executemany(). You pass executemany() a SQL statement and a list of items to use with that SQL statement. While there are other ways of inserting data, using the “?” syntax as you did in the example above is the preferred way of passing values to the cursor as it prevents SQL injection attacks.

If you’d like to learn more about SQL Injection, Wikipedia is a good place to start:

Now you have data in your table, but you don’t have a way to actually view that data. You will find out how to do that next!

Searching Your Database

Extracting data from a database is done primarily with the SELECT, FROM, and WHERE keywords. You will find that these commands are not too hard to use. You should create a new file named queries.py and enter the following code into it:

import sqlite3

def get_cursor():
    conn = sqlite3.connect("library.db")
    return conn.cursor()

def select_all_records_by_author(cursor, author):
    sql = "SELECT * FROM books WHERE author=?"
    cursor.execute(sql, [author])
    print(cursor.fetchall())  # or use fetchone()
    print("\nHere is a listing of the rows in the table\n")
    for row in cursor.execute("SELECT rowid, * FROM books ORDER BY author"):
        print(row)

def select_using_like(cursor, text):
    print("\nLIKE query results:\n")
    sql = f"""
    SELECT * FROM books
    WHERE title LIKE '{text}%'"""
    cursor.execute(sql)
    print(cursor.fetchall())

if __name__ == '__main__':
    cursor = get_cursor()
    select_all_records_by_author(cursor,
                                 author='Mike Driscoll')
    select_using_like(cursor, text='Python')

This code is a little long, so we will go over each function individually. Here is the first bit of code:

import sqlite3

def get_cursor():
    conn = sqlite3.connect("library.db")
    return conn.cursor()

The get_cursor() function is a useful function for connecting to the database and returning the cursor object. You could make it more generic by passing it the name of the database you wish to open.

The next function will show you how to get all the records for a particular author in the database table:

def select_all_records_by_author(cursor, author):
    sql = "SELECT * FROM books WHERE author=?"
    cursor.execute(sql, [author])
    print(cursor.fetchall())  # or use fetchone()
    print("\nHere is a listing of the rows in the table\n")
    for row in cursor.execute("SELECT rowid, * FROM books ORDER BY author"):
        print(row)

To get all the records from a database, you would use the following SQL command: SELECT * FROM books. SELECT, by default, returns the requested fields from every record in the database table. The asterisk is a wildcard character which means “I want all the fields”. So SELECT and * combined will return all the data currently in a table. You usually do not want to do that! Tables can become quite large and trying to pull everything from it at once may adversely affect your database’s, or your computer’s, performance. Instead, you can use the WHERE clause to filter the SELECT to something more specific, and/or only select the fields you are interested in.

In this example, you filter the SELECT to a specific author. You are still selecting all the records, but it is unlikely for a single author to have contributed to too many rows to negatively affect performance. You then tell the cursor to fetchall(), which will fetch all the results from the SELECT call you made. You could use fetchone() to fetch only the first result from the SELECT.

The last two lines of code fetch all the entries in the books table along with their rowids, and orders the results by the author name. The output from this function looks like this:

Here is a listing of the rows in the table

(3, 'Automate the Boring Stuff with Python', 'Al Sweigart', '', 'No Starch Press', 'PDF')
(4, 'The Well-Grounded Python Developer', 'Doug Farrell', '2020', 'Manning', 'Kindle')
(1, 'Python 101', 'Mike Driscoll', '9/01/2020', 'Mouse Vs Python', 'epub')
(2, 'Python Interviews', 'Mike Driscoll', '2/1/2018', 'Packt Publishing', 'softcover')

You can see that when you sort by author, it sorts using the entire string rather than by the last name. If you are looking for a challenge, you can try to figure out how you might store the data to make it possible to sort by the last name. Alternatively, you could write more complex SQL queries or process the results in Python to sort it in a nicer way.

The last function to look at is select_using_like():

def select_using_like(cursor, text):
    print("\nLIKE query results:\n")
    sql = f"""
    SELECT * FROM books
    WHERE title LIKE '{text}%'"""
    cursor.execute(sql)
    print(cursor.fetchall())

This function demonstrates how to use the SQL command LIKE, which is kind of a filtered wildcard search. In this example, you tell it to look for a specific string with a percent sign following it. The percent sign is a wildcard, so it will look for any record that has a title that starts with the passed-in string.

When you run this function with the text set to “Python”, you will see the following output:

LIKE query results:

[('Python 101', 'Mike Driscoll', '9/01/2020', 'Mouse Vs Python', 'epub'), 
('Python Interviews', 'Mike Driscoll', '2/1/2018', 'Packt Publishing', 'softcover')]

The last few lines of code are here to demonstrate what the functions do:

if __name__ == '__main__':
    cursor = get_cursor()
    select_all_records_by_author(cursor,
                                 author='Mike Driscoll')
    select_using_like(cursor, text='Python')

Here you grab the cursor object and pass it in to the other functions. Remember, you use the cursor to send commands to your database. In this example, you set the author for select_all_records_by_author() and the text for select_using_like(). These functions are a good way to make your code reusable.

Now you are ready to learn how to update data in your database!

Editing Data in Your Database

When it comes to editing data in a database, you will almost always be using the following SQL commands:

  • UPDATE – Used for updating a specific database table
  • SET – Used to update a specific field in the database table

UPDATE, just like SELECT, works on all records in a table by default. Remember to use WHERE to limit the scope of the command!

To see how this works, create a file named update_record.py and add this code:

# update_record.py

import sqlite3

def update_author(old_name, new_name):
    conn = sqlite3.connect("library.db")
    cursor = conn.cursor()
    sql = f"""
    UPDATE books
    SET author = '{new_name}'
    WHERE author = '{old_name}'
    """
    cursor.execute(sql)
    conn.commit()

if __name__ == '__main__':
    update_author(
            old_name='Mike Driscoll',
            new_name='Michael Driscoll',
            )

In this example, you create update_author() which takes in the old author name to look for and the new author name to change it to. Then you connect to the database and create the cursor as you have in the previous examples. The SQL code here tells your database that you want to update the books table and set the author field to the new name where the author name currently equals the old name. Finally, you execute() and commit() the changes.

To test that this code worked, you can re-run the query code from the previous section and examine the output.

Now you’re ready to learn how to delete data from your database!

Deleting Data From Your Database

Sometimes data must be removed from a database. For example, if you decide to stop being a customer at a bank, you would expect them to purge your information from their database after a certain period of time had elapsed. To delete from a database, you can use the DELETE command.

Go ahead and create a new file named delete_record.py and add the following code to see how deleting data works:

# delete_record.py

import sqlite3

def delete_author(author):
    conn = sqlite3.connect("library.db")
    cursor = conn.cursor()

    sql = f"""
    DELETE FROM books
    WHERE author = '{author}'
    """
    cursor.execute(sql)
    conn.commit()

if __name__ == '__main__':
    delete_author(author='Al Sweigart')

Here you create delete_author() which takes in the name of the author that you wish to remove from the database. The code in this example is nearly identical to the previous example except for the SQL statement itself. In the SQL query, you use DELETE FROM to tell the database which table to delete data from. Then you use the WHERE clause to tell it which field to use to select the target records. In this case, you tell your database to remove any records from the books table that match the author name.

You can verify that this code worked using the SQL query code from earlier in this article.

Wrapping Up

Working with databases can be a lot of work. This article covered only the basics of working with databases. Here you learned how to do the following:

  • Creating a SQLite Database
  • Adding Data to Your Database
  • Searching Your Database
  • Editing Data in Your Database
  • Deleting Data From Your Database

If you find SQL code a bit difficult to understand, you might want to check out an “object-relational mapper” package, such as SQLAlchemy or SQLObject. An object-relational mapper (ORM) turns Python statements into SQL code for you so that you are only writing Python code. Sometimes you may still need to drop down to bare SQL to get the efficiency you need from the database, but these ORMs can help speed up development and make things easier.

Here are some links for those two projects:

Related Tutorials

The post Python 101 – How to Work with a Database Using sqlite3 appeared first on Mouse Vs Python.



from Planet Python
via read more

Python Anywhere: Async work in Web Apps or – Have Your Cake and Eat It Too

This post is intended for users who begin their adventure with web applications. You’ll find below how to structure a web app that relies on heavy processing of the input data – processing that takes so long that you can’t do it inside a request handler with a five-minute timeout, or at least so long that you don’t want to risk slowing down your website by doing it inside the website’s own code. You want it to happen in the background. You’ll see an example implementing some hints from the “Async work in Web apps” help page, which involve writing a jQuery script polling simple API endpoint communicating with a database updated by an external script (so there will be some sqlalchemy stuff too).



from Planet Python
via read more

Wednesday, September 29, 2021

Podcast.__init__: Accelerating Drug Discovery Using Machine Learning With TorchDrug

Finding new and effective treatments for disease is a complex and time consuming endeavor, requiring a high degree of domain knowledge and specialized equipment. Combining his expertise in machine learning and graph algorithms with is interest in drug discovery Jian Tang created the TorchDrug project to help reduce the amount of time needed to find new candidate molecules for testing. In this episode he explains how the project is being used by machine learning researchers and biochemists to collaborate on finding effective treatments for real-world diseases.

Summary

Finding new and effective treatments for disease is a complex and time consuming endeavor, requiring a high degree of domain knowledge and specialized equipment. Combining his expertise in machine learning and graph algorithms with is interest in drug discovery Jian Tang created the TorchDrug project to help reduce the amount of time needed to find new candidate molecules for testing. In this episode he explains how the project is being used by machine learning researchers and biochemists to collaborate on finding effective treatments for real-world diseases.

Announcements

  • Hello and welcome to Podcast.__init__, the podcast about Python’s role in data and science.
  • When you’re ready to launch your next app or want to try a project you hear about on the show, you’ll need somewhere to deploy it, so take a look at our friends over at Linode. With the launch of their managed Kubernetes platform it’s easy to get started with the next generation of deployment and scaling, powered by the battle tested Linode platform, including simple pricing, node balancers, 40Gbit networking, dedicated CPU and GPU instances, and worldwide data centers. Go to pythonpodcast.com/linode and get a $100 credit to try out a Kubernetes cluster of your own. And don’t forget to thank them for their continued support of this show!
  • Your host as usual is Tobias Macey and today I’m interviewing Jian Tang about TorchDrug

Interview

  • Introductions
  • How did you get introduced to Python?
  • Can you describe what TorchDrug is and the story behind it?
  • What are the goals of the TorchDrug project?
    • Who are the target users of the project?
    • What are the main ways that it is being used?
  • What are the challenges faced by biologists and chemists working on development and discovery of pharmaceuticals?
    • What are some of the other tools/techniques that they would use (in isolation or combination with TorchDrug)?
  • Can you describe how TorchDrug is implemented?
    • How have you approached the design of the project and its APIs to make it accessible to engineers that don’t possess domain expertise in drug discovery research?
  • How do graph structures help when modeling and experimenting with chemical structures for drug discovery?
  • What are the formats and sources of data that you are working with?
    • What are some of the complexities/challenges that you have had to deal with to integrate with up or downstream systems to fit into the overall research process?
  • Can you talk through the workflow of using TorchDrug to build and validate a model?
    • What is involved in determining and codifying a goal state for the model to optimize for?
  • What are the biggest open questions in the area of drug discovery and research?
    • How is TorchDrug being used to assist in the exploration of those problems?
  • What are the most interesting, unexpected, or challenging lessons that you have learned while working on TorchDrug?
  • When is TorchDrug the wrong choice?
  • What do you have planned for the future of TorchDrug?

Keep In Touch

Picks

  • Tobias
    • Rope refactoring library
  • Jian
    • Attending conferences once the pandemic is over

Closing Announcements

  • Thank you for listening! Don’t forget to check out our other show, the Data Engineering Podcast for the latest on modern data management.
  • Visit the site to subscribe to the show, sign up for the mailing list, and read the show notes.
  • If you’ve learned something or tried out a project from the show then tell us about it! Email hosts@podcastinit.com) with your story.
  • To help other people find the show please leave a review on iTunes and tell your friends and co-workers
  • Join the community in the new Zulip chat workspace at pythonpodcast.com/chat

Links

The intro and outro music is from Requiem for a Fish The Freak Fandango Orchestra / CC BY-SA



from Planet Python
via read more

Python Bytes: #252 Jupyter is now a desktop app!

<p><strong>Watch the live stream:</strong></p> <a href='https://www.youtube.com/watch?v=3SMItn5bfKs' style='font-weight: bold;'>Watch on YouTube</a><br> <br> <p><strong>About the show</strong></p> <p>Sponsored by <strong>us:</strong></p> <ul> <li>Check out the <a href="https://training.talkpython.fm/courses/all"><strong>courses over at Talk Python</strong></a></li> <li>And <a href="https://pythontest.com/pytest-book/"><strong>Brian’s book too</strong></a>!</li> </ul> <p>Special guest: <strong>Ethan Swan</strong> </p> <p><strong>Michael #0: <a href="https://twitter.com/shacharmirkin/status/1441291234937491459">Changing themes to DIY</a></strong></p> <p><strong>Brian #1:</strong> <a href="https://www.sqlfluff.com/"><strong>SQLFluff</strong></a></p> <ul> <li>Suggested by Dave Kotchessa.</li> <li>A SQL Linter, written in Python, tested with pytest</li> <li>Configurable, and configuration can live in many places including <code>tox.ini</code> and <code>pyproject.toml</code>.</li> <li><a href="https://docs.sqlfluff.com/en/stable/">Great docs</a></li> <li><a href="https://docs.sqlfluff.com/en/stable/rules.html">Rule reference</a> with anti-pattern/best practice format</li> <li>Includes dialects for ANSI, PostgreSQL, MySQL, Teradata, BigQuery, Snoflake</li> <li>Note in docs: “<strong>SQLFluff</strong> is still in an open alpha phase - expect the tool to change significantly over the coming months, and expect potentially non-backward compatible api changes to happen at any point.”</li> </ul> <p><strong>Michael #2:</strong> <a href="https://blog.jupyter.org/jupyterlab-desktop-app-now-available-b8b661b17e9a"><strong>JupyterLab Desktop</strong></a></p> <ul> <li><a href="https://github.com/jupyterlab/jupyterlab_app">JupyterLab App</a> is the cross-platform standalone application distribution of <a href="https://github.com/jupyterlab/jupyterlab">JupyterLab</a>.</li> <li>Bundles a Python environment with several popular Python libraries ready to use in scientific computing and data science workflows.</li> <li>JupyterLab App works on Debian and Fedora based Linux, macOS and Windows operating systems.</li> </ul> <p><strong>Ethan #3:</strong> <a href="https://github.com/reclosedev/requests-cache/"><strong>Requests Cache</strong></a></p> <ul> <li>Create a requests_cache session and call HTTP methods from there <ul> <li>You can also do it without a session but that’s a bit weird, looks like it’s monkey patching requests or something…</li> </ul></li> <li>Results are cached</li> <li>Very handy for repeatedly calling endpoints <ul> <li>especially if the returned data is large, or the server has to do some compute</li> </ul></li> <li>Reminds me of @functools.lru_cache </li> <li>Can set things like how long the cache should last (when to invalidate)</li> <li>Funny easter egg in example: “# Cache 400 responses as a solemn reminder of your failures”</li> </ul> <p><strong>Brian #4:</strong> <a href="https://github.com/simonw/pypi-rename"><strong>pypi-rename</strong></a></p> <ul> <li>This is a cookiecutter template from Simon Willison</li> <li>Backstory: <ul> <li>To refresh my memory on how to publish a new package with flit I created <a href="https://pypi.org/project/pytest-skip-slow/">a new pytest plugin</a>.</li> <li>Brian Skinn noticed it somehow, and suggested a better name. Thanks Brian.</li> <li>So, how to nicely rename. I searched and found Simon’s template, which is…</li> </ul></li> <li>A cookiecutter template. So you can use cookiecutter to do some of this work for you.</li> <li>But it’s based on setuptools, and I kinda like flit lately, so I just used the instructions.</li> <li>The README.md includes instructions for the steps needed: <ul> <li>Create renamed version</li> <li>Publish under new name</li> <li>Change old one to depend on new one, but be mostly empty</li> <li>Modify readme to tell people what's going on</li> <li>Publish old name as a notice</li> </ul></li> <li>Now people looking for old one will find new one.</li> <li>People just installing old one will end up with new one also since it’s a dependency.</li> </ul> <p><strong>Michael #5:</strong> <a href="https://github.com/django/django/pull/14437"><strong>Django 4 coming with Redis Adapter</strong></a></p> <ul> <li>#33012 closed New feature (fixed) → Add a Redis cache backend. </li> <li>Adds support for Redis to be used as a caching backend with Django. </li> <li>Redis is the most popular caching backend, adding it to django.core.cache module would be a great addition for developers who previously had to rely on the use of third party packages.</li> <li>It will be simpler than that provided by <code>django-redis</code>, for instance customising the serialiser is out-of-scope for the initial pass.</li> </ul> <p><strong>Ethan #6:</strong> <a href="https://www.python.org/dev/peps/pep-0612/"><strong>PEP 612</strong></a></p> <ul> <li>It wasn’t possible to type a function that took in a function and returned a function with the same signature (which is what many decorators do) <ul> <li>This creates a ParamSpec – which is much like a TypeVar, for anyone who has used them to type generic functions/classes</li> </ul></li> <li>It’s a reminder that typing is still missing features and evolving, and it’s good to accept the edge cases for now – “gradual typing” <ul> <li>Reading Fluent Python by Ramalho has influenced my view on this – don’t lose your mind trying to type crazy stuff, just accept that it’s “gradual”</li> </ul></li> <li>Mention how typing is still evolving in Python and it’s good to keep an eye out for new features that help you (see also <a href="https://www.python.org/dev/peps/pep-0645/">PEP 645</a> – using <code>int?</code> for <code>Optional[int]</code>; and <a href="https://www.python.org/dev/peps/pep-0655/">PEP 655</a> – annotating some TypedDict keys as required and others not required)</li> </ul> <p><strong>Extras</strong></p> <p><strong>Michael</strong></p> <ul> <li><a href="https://twitter.com/AntonioAndrade/status/1440637306558316546"><strong>Earsketch</strong></a></li> <li><strong>Django Critical CVE:</strong> <a href="https://github.com/advisories/GHSA-xpfp-f569-q3p2"><strong>CVE-2021-35042</strong></a> <ul> <li><strong>Vulnerable versions:</strong> &gt;= 3.0.0, &lt; 3.1.13</li> <li><strong>Patched version:</strong> 3.1.13</li> <li>Django 3.1.x before 3.1.13 and 3.2.x before 3.2.5 allows QuerySet.order_by SQL injection if order_by is untrusted input from a client of a web application.</li> </ul></li> </ul> <p><strong>Ethan</strong></p> <ul> <li><a href="https://github.com/spotify/pedalboard"><strong>Pedalboard</strong></a> <ul> <li>I happened upon this project recently and checked back, only to see that Brett Cannon was the last committer! A doc fix, like he suggested last episode</li> </ul></li> </ul> <p>Brian</p> <ul> <li><a href="https://docs.python.org/3.11/whatsnew/3.11.html#optimizations"><strong>Zero Cost Exceptions in Python 3.11</strong></a> <ul> <li>Suggested by John Hagen</li> <li>Guido, Mark Shannon, and others at Microsoft are working on speeding up Python</li> <li><a href="https://github.com/faster-cpython/ideas">faster-cpython/ideas repo</a> includes a slide deck from Guido which includes “Zero overhead” exception handling.</li> <li><a href="https://docs.python.org/3.11/whatsnew/3.11.html#optimizations">Python 3.11 “What’s New” page, Optimizations section</a> includes:</li> <li>“Zero-cost” exceptions are implemented. The cost of <code>try</code> statements is almost eliminated when no exception is raised. (Contributed by Mark Shannon in <a href="https://bugs.python.org/issue40222">bpo-40222</a>.)</li> <li>MK: I <a href="https://gist.github.com/mikeckennedy/f516c9cf2f7a69a02a815e3799b42f95"><strong>played with this a bit</strong></a>.</li> </ul></li> </ul> <p><strong>Joke:</strong> <a href="https://geek-and-poke.com/geekandpoke/2021/1/31/qa-101"><strong>QA 101</strong></a></p>

from Planet Python
via read more

Securing the Open-Source Pipeline with Anaconda CVE Curation

Take advantage of Anaconda Team Edition to secure your open-source pipeline so your team can spend more time building models, analyzing data, and making data-driven decisions.

from Planet SciPy
read more

Real Python: Hosting a Django Project on Heroku

As a novice web developer, you’ve built your portfolio app and shared your code on GitHub. Perhaps, you’re hoping to attract technical recruiters to land your first programming job. Many coding bootcamp graduates are likely doing the same thing. To differentiate yourself from the crowd and boost your chances of getting noticed, you can start hosting your Django project online.

For a hobby Django project, you’ll want a hosting service that’s free of charge, quick to set up, user-friendly, and well-integrated with your existing technology stack. While GitHub Pages is perfect for hosting static websites and websites with JavaScript, you’ll need a web server to run your Flask or Django project.

There are a few major cloud platform providers operating in different models, but you’re going to explore Heroku in this tutorial. It ticks all the boxes—it’s free, quick to set up, user-friendly, and well-integrated with Django—and is the favorite cloud platform provider of many startups.

In this tutorial, you’ll learn how to:

  • Take your Django project online in minutes
  • Deploy your project to Heroku using Git
  • Use a Django-Heroku integration library
  • Hook your Django project up to a standalone relational database
  • Manage the configuration along with sensitive data

To follow along, you can download the code and other resources by clicking the link below:

Demo: What You’ll Build

You’re going to create a bare-bones Django project and deploy it to the cloud straight from the terminal. By the end, you’ll have a public and shareable link to your first Heroku app.

Here’s a one-minute video demonstrating the necessary steps, from initializing an empty Git repository to viewing your finished project in the browser. Hang on and watch till the end for a quick preview of what you’re about to find in this tutorial:

In addition to the steps shown in the screencast above, you’ll find a few more later on, but this should be enough to give you a general idea about how you’ll be working with Heroku in this tutorial.

Project Overview

This tutorial isn’t so much about building any particular project, but rather hosting one in the cloud using Heroku. While Heroku supports various languages and web frameworks, you’ll stick to Python and Django. Don’t worry if you don’t have any Django projects on hand. The first step will walk you through scaffolding a new Django project to get you started quickly. Alternatively, you can use a ready-made sample project that you’ll find later.

Once you have your Django project ready, you’re going to sign up for a free Heroku account. Next, you’ll download a convenient command-line tool that will help you manage your apps online. As demonstrated in the screencast above, the command line is a quick way of working with Heroku. Finally, you’ll finish off with a deployed Django project hosted on your newly-configured Heroku instance. You can think of your final result as a placeholder for your future project ideas.

Prerequisites

Before jumping ahead, make sure that you’re familiar with the basics of the Django web framework and that you’re comfortable using it to set up a bare-bones project.

Note: If you’re more experienced with Flask than Django, then you can check out a similar tutorial about Deploying a Python Flask Example Application Using Heroku.

You should also have a Git client installed and configured so that you can interact conveniently with the Heroku platform from the command line. Finally, you should seriously consider using a virtual environment for your project. If you don’t already have a specific virtual environment tool in mind, you’ll find some options in this tutorial soon.

Step 1: Scaffold a Django Project for Hosting

To host a Django web application in the cloud, you need a working Django project. For the purposes of this tutorial, it doesn’t have to be elaborate. Feel free to use one of your hobby projects or to build a sample portfolio app if you’re short on time, and then skip ahead to creating your local Git repository. Otherwise, stick around to make a brand new project from scratch.

Create a Virtual Environment

It’s a good habit to start every project by creating an isolated virtual environment that won’t be shared with other projects. This can keep your dependencies organized and help avoid package version conflicts. Some dependency managers and packaging tools like Pipenv or poetry automatically create and manage virtual environments for you to follow best practices. Many IDEs like PyCharm do this by default, too, when you’re starting a new project.

However, the most reliable and portable way of creating a Python virtual environment is to do it manually from the command line. You can use an external tool such as virtualenvwrapper or call the built-in venv module directly. While virtualenvwrapper keeps all environments in a predefined parent folder, venv expects you to specify a folder for every environment separately.

You’ll be using the standard venv module in this tutorial. It’s customary to place the virtual environment in the project root folder, so let’s make one first and change the working directory to it:

Read the full article at https://realpython.com/django-hosting-on-heroku/ »


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]



from Planet Python
via read more

Hosting a Django Project on Heroku

As a novice web developer, you’ve built your portfolio app and shared your code on GitHub. Perhaps, you’re hoping to attract technical recruiters to land your first programming job. Many coding bootcamp graduates are likely doing the same thing. To differentiate yourself from the crowd and boost your chances of getting noticed, you can start hosting your Django project online.

For a hobby Django project, you’ll want a hosting service that’s free of charge, quick to set up, user-friendly, and well-integrated with your existing technology stack. While GitHub Pages is perfect for hosting static websites and websites with JavaScript, you’ll need a web server to run your Flask or Django project.

There are a few major cloud platform providers operating in different models, but you’re going to explore Heroku in this tutorial. It ticks all the boxes—it’s free, quick to set up, user-friendly, and well-integrated with Django—and is the favorite cloud platform provider of many startups.

In this tutorial, you’ll learn how to:

  • Take your Django project online in minutes
  • Deploy your project to Heroku using Git
  • Use a Django-Heroku integration library
  • Hook your Django project up to a standalone relational database
  • Manage the configuration along with sensitive data

To follow along, you can download the code and other resources by clicking the link below:

Demo: What You’ll Build

You’re going to create a bare-bones Django project and deploy it to the cloud straight from the terminal. By the end, you’ll have a public and shareable link to your first Heroku app.

Here’s a one-minute video demonstrating the necessary steps, from initializing an empty Git repository to viewing your finished project in the browser. Hang on and watch till the end for a quick preview of what you’re about to find in this tutorial:

In addition to the steps shown in the screencast above, you’ll find a few more later on, but this should be enough to give you a general idea about how you’ll be working with Heroku in this tutorial.

Project Overview

This tutorial isn’t so much about building any particular project, but rather hosting one in the cloud using Heroku. While Heroku supports various languages and web frameworks, you’ll stick to Python and Django. Don’t worry if you don’t have any Django projects on hand. The first step will walk you through scaffolding a new Django project to get you started quickly. Alternatively, you can use a ready-made sample project that you’ll find later.

Once you have your Django project ready, you’re going to sign up for a free Heroku account. Next, you’ll download a convenient command-line tool that will help you manage your apps online. As demonstrated in the screencast above, the command line is a quick way of working with Heroku. Finally, you’ll finish off with a deployed Django project hosted on your newly-configured Heroku instance. You can think of your final result as a placeholder for your future project ideas.

Prerequisites

Before jumping ahead, make sure that you’re familiar with the basics of the Django web framework and that you’re comfortable using it to set up a bare-bones project.

You should also have a Git client installed and configured so that you can interact conveniently with the Heroku platform from the command line. Finally, you should seriously consider using a virtual environment for your project. If you don’t already have a specific virtual environment tool in mind, you’ll find some options in this tutorial soon.

Step 1: Scaffold a Django Project for Hosting

To host a Django web application in the cloud, you need a working Django project. For the purposes of this tutorial, it doesn’t have to be elaborate. Feel free to use one of your hobby projects or to build a sample portfolio app if you’re short on time, and then skip ahead to creating your local Git repository. Otherwise, stick around to make a brand new project from scratch.

Create a Virtual Environment

It’s a good habit to start every project by creating an isolated virtual environment that won’t be shared with other projects. This can keep your dependencies organized and help avoid package version conflicts. Some dependency managers and packaging tools like Pipenv or poetry automatically create and manage virtual environments for you to follow best practices. Many IDEs like PyCharm do this by default, too, when you’re starting a new project.

However, the most reliable and portable way of creating a Python virtual environment is to do it manually from the command line. You can use an external tool such as virtualenvwrapper or call the built-in venv module directly. While virtualenvwrapper keeps all environments in a predefined parent folder, venv expects you to specify a folder for every environment separately.

You’ll be using the standard venv module in this tutorial. It’s customary to place the virtual environment in the project root folder, so let’s make one first and change the working directory to it:

Read the full article at https://realpython.com/django-hosting-on-heroku/ »


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]



from Real Python
read more

TestDriven.io: Django REST Framework Views - Generic Views

This article looks at how to use Django REST Framework's Generic Views to prevent repeating certain patterns over and over again.

from Planet Python
via read more

Python for Beginners: Bitwise Shift Operators in Python

There are various types of operators like arithmetic operators, comparison operators, and bitwise operators in Python. In our programs, we use these operators to control the sequence of execution and to manipulate the data. In this article, we will study different python bitwise shift operators, their functioning and examples.

What are Bitwise shift operators?

Bitwise shift operators are binary operators. These operators are used to shift bits of a binary representation of a number to left or right by certain places. Bitwise shift operators are often used for operations in which we have to multiply or divide an integer by powers of 2. Here, the Bitwise left shift operator is used for multiplying a number by powers of 2 while the bitwise right shift operator in python is used to divide a number by powers of 2.  

Bitwise Right Shift Operator in Python

The bitwise right shift operator in python shifts the bits of the binary representation of the input number to the right side by a specified number of places. The empty bits created by shifting the bits are filled by 0s.  

The syntax for the bitwise right shift is a >> n. Here ‘a’ is the number whose bits will be shifted by ‘n’ places to the right.

The working of bitwise right shift operation can be understood from the following illustration.

Suppose we have to shift the bits of 14 by 2 places. We will first convert it into binary format.

  • 14 in binary format is written as 1110.

After shifting, the two rightmost bits 1 and 0 will be discarded and the empty leftmost bits will be filled with 0s. The output of 14 >> 2 will be 0011 in binary which converts to the value 3 in integer format. 

Here you can observe that we have shifted the bits by 2 places due to which the input number has been divided by 22 i.e. 4. Similarly, if we right shift the number by n bits, the integer value of the number will be divided by 2n.  We can verify this output using the right shift operator in python using the following program.

myNum1 = 14
myNum2 = 2
shiftNum = myNum1 >> myNum2
print("Operand 1 is:", myNum1)
print("operand 2 is:", myNum2)
print("Result of the right shift operation on {} by {} bits is {}.".format(myNum1, myNum2, shiftNum))

Output:

Operand 1 is: 14
operand 2 is: 2
Result of the right shift operation on 14 by 2 bits is 3.

Bitwise Left Shift Operator in Python

The bitwise left shift operator in Python shifts the bits of the binary representation of the input number to the left side by a specified number of places. The empty bits created by shifting the bits are filled by 0s.  

The syntax for the bitwise left shift is a << n. Here ‘a’ is the number whose bits will be shifted by ‘n’ places to the left.

The working of bitwise left shift operation can be understood from the following illustration.

Suppose we have to shift the bits of 14 by 2 places. We will first convert it into binary format.

  • 14 in binary format is written as 1110.

After shifting, the empty rightmost bits will be filled with 0s. The output of 14 << 2 will be 111000 in binary which converts to the value 56 in integer format. 

Here you can observe that we have shifted the bits by 2 places due to which the input number has been multiplied by 22 i.e. 4. Similarly, if we left shift the number by n bits, the integer value of the number will be multiplied by 2n.  We can verify this output using the left shift operator in python using the following program.

myNum1 = 14
myNum2 = 2
shiftNum = myNum1 << myNum2
print("Operand 1 is:", myNum1)
print("operand 2 is:", myNum2)
print("Result of the left shift operation on {} by {} bits is {}.".format(myNum1, myNum2, shiftNum))

Output:

Operand 1 is: 14
operand 2 is: 2
Result of the left shift operation on 14 by 2 bits is 56.

Conclusion

In this article, we have discussed bitwise shift operators, their syntax and examples in Python. To learn more about python programming, you can read this article on list comprehension. You may also like this article on the linked list in Python.

The post Bitwise Shift Operators in Python appeared first on PythonForBeginners.com.



from Planet Python
via read more

Mike Driscoll: Python 101 – How to Create a Graphical User Interface

When you first get started as a programmer or software developer, you usually start by writing code that prints to your console or standard out. A lot of students are also starting out by writing front-end programs, which are typically websites written with HTML, JavaScript and CSS. However, most beginners do not learn how to create a graphical user interface until much later in their classwork.

Graphical user interfaces (GUI) are programs that are usually defined as created for the desktop. The desktop refers to Windows, Linux and MacOS. It could be argued that GUIs are also created for mobile and web as well though. For the purposes of this article, you will learn about creating desktop GUIs. The concepts you learn in this article can be applied to mobile and web development to some degree as well.

A graphical user interface is made up of some kind of window that the user interacts with. The window holds other shapes inside it. These consist of buttons, text, pictures, tables, and more. Collectively, these items are known as “widgets”.

There are many different GUI toolkits for Python. Here is a list of some of the most popular:

  • Tkinter
  • wxPython
  • PyQt
  • Kivy

You will be learning about wxPython in this article. The reason that wxPython was chosen is that the author has more experience with it than any other and wxPython has a very friendly and helpful community.

In this article, you will be learning:

  • Learning About Event Loops
  • How to Create Widgets
  • How to Lay Out Your Application
  • How to Add Events
  • How to Create an Application

This article does not attempt to cover everything there is to know about wxPython. However, you will learn enough to see the power of wxPython as well as discover how much fun it is to create a desktop GUI of your very own.

Note: Some of the examples in this chapter come from my book, Creating GUI Applications with wxPython.

Let’s get started!

Installing wxPython

Installing wxPython is usually done with pip. If you are installing on Linux, you may need to install some prerequisites before installing wxPython. You can see the most up-to-date set of requirements on the wxPython Github page.

On Mac OSX, you may need the XCode compiler to install wxPython.

Here is the command you would use to install wxPython using pip:

python3 -m pip install wxpython

Assuming everything worked, you should now be able to use wxPython!

Learning About Event Loops

Before you get started, there is one other item that you need to know about. In the introduction, you learned what widgets are. But when it comes to creating GUI programs, you need to understand that they use events to tell the GUI what to do. Unlike a command-line application, a GUI is basically an infinite loop, waiting for the user to do something, like click a button or press a key on the keyboard.

When the user does something like that, the GUI receives an event. Button events are usually connected to wx.EVT_BUTTON, for example. Some books call this event-driven programming. The overarching process is called the event loop.

You can think of it like this:

  1. The GUI waits for the user to do something
  2. The user does something (clicks a button, etc)
  3. The GUI responds somehow
  4. Go back to step 1

The user can stop the event loop by exiting the program.

Now that you have a basic understanding of event loops, it’s time to learn how to write a simple prototype application!

How to Create Widgets

Widgets are the building blocks of your application. You start out with top-level widgets, such as a wx.Frame or a wx.Dialog. These widgets can contain other widgets, like buttons and labels. When you create a frame or dialog, it includes a title bar and the minimize, maximize, and exit buttons. Note that when using wxPython, most widgets and attributes are pre-fixed with wx.

To see how this all works, you should create a little “Hello World” application. Go ahead and create a new file named hello_wx.py and add this code to it:

# hello_wx.py

import wx

app = wx.App(False)
frame = wx.Frame(parent=None, title='Hello World')
frame.Show()
app.MainLoop()

Here you import wx, which is how you access wxPython in your code. Then you create an instance of wx.App(), which is your Application object. There can only be one of these in your application. It creates and manages your event loop for you. You pass in False to tell it not to redirect standard out. If you set that to True, then standard out is redirected to a new window. This can be useful when debugging, but should be disabled in production applications.

Next, you create a wx.Frame() where you set its parent to None. This tells wxPython that this frame is a top-level window. If you create all your frames without a parent, then you will need to close all the frames to end the program. The other parameter that you set is the title, which will appear along the top of your application’s window.

The next step is to Show() the frame, which makes it visible to the user. Finally, you call MainLoop() which starts the event loop and makes your application work. When you run this code, you should see something like this:

Hello World in wxPythonHello World in wxPython

When working with wxPython, you will actually be sub-classing wx.Frame and quite a few of the other widgets. Create a new file named hello_wx_class.py and put this code into it:

# hello_wx_class.py

import wx

class MyFrame(wx.Frame):
    
    def __init__(self):
        super().__init__(None, title='Hello World')
        self.Show()

if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

This code does the same thing as the previous example, but this time you are creating your own version of the wx.Frame class.

When you create an application with multiple widgets in it, you will almost always have a wx.Panel as the sole child widget of the wx.Frame. Then the wx.Panel widget is used to contain the other widgets. The reason for this is that wx.Panel provides the ability to tab between the widgets, which is something that does not work if you make all the widget children of wx.Frame.

So, for a final “Hello World” example, you can add a wx.Panel to the mix. Create a file named hello_with_panel.py and add this code:

# hello_with_panel.py

import wx

class MyPanel(wx.Panel):
    
    def __init__(self, parent):
        super().__init__(parent)
        button = wx.Button(self, label='Press Me')

class MyFrame(wx.Frame):
    
    def __init__(self):
        super().__init__(None, title='Hello World')
        panel = MyPanel(self)
        self.Show()

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    app.MainLoop()

In this code, you create two classes. One sub-classes wx.Panel and adds a button to it using wx.Button. The MyFrame() class is almost the same as the previous example except that you now create an instance of MyPanel() in it. Note that you are passing self to MyPanel(), which is telling wxPython that the frame is now the parent of the panel widget.

When you run this code, you will see the following application appear:

Hello World with a wxPython PanelHello World with a wxPython Panel

This example shows that when you add a child widget, like a button, it will automatically appear at the top left of the application. The wx.Panel is an exception when it is the only child widget of a wx.Frame. In that case, the wx.Panel will automatically expand to fill the wx.Frame.

What do you think happens if you add multiple widgets to the panel though? Let’s find out! Create a new file named stacked_buttons.py and add this code:

# stacked_buttons.py

import wx

class MyPanel(wx.Panel):
    
    def __init__(self, parent):
        super().__init__(parent)
        button = wx.Button(self, label='Press Me')
        button2 = wx.Button(self, label='Press Me too')
        button3 = wx.Button(self, label='Another button')

class MyFrame(wx.Frame):
    
    def __init__(self):
        super().__init__(None, title='Hello World')
        panel = MyPanel(self)
        self.Show()


if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    app.MainLoop()

Now you have three buttons as children of the panel. Try running this code to see what happens:

Stacked Buttons in wxPython

Oops! You only see one button, which happens to be the last one you created. What happened here? You didn’t tell the buttons where to go, so they all went to the default location, which is the upper left corner of the widget. In essence, the widgets are now stacked on top of each other.

Let’s find out how you can fix that issue in the next section!

How to Lay Out Your Application

You have two options when it comes to laying out your application:

  • Absolute positioning
  • Sizers

In almost all cases, you will want to use Sizers. If you want to use absolute positioning, you can use the widget’s pos parameter and give it a tuple that specifies the x and y coordinate in which to place the widget. Absolute positioning can be useful when you need pixel perfect positioning of widgets. However, when you use absolute positioning, your widgets cannot resize or move when the window they are in is resized. They are static at that point.

The solution to those issues is to use Sizers. They can handle how your widgets should resize and adjust when the application size is changed. There are several different sizers that you can use, such as wx.BoxSizer, wx.GridSizer, and more.

The wxPython documentation explains how sizers work in detail. Check it out when you have a chance.

Let’s take that code from before and reduce it down to two buttons and add a Sizer. Create a new file named sizer_with_two_widgets.py and put this code into it:

# sizer_with_two_widgets.py

import wx

class MyPanel(wx.Panel):

    def __init__(self, parent):
        super().__init__(parent)

        button = wx.Button(self, label='Press Me')
        button2 = wx.Button(self, label='Second button')

        main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(button, proportion=1,
                       flag=wx.ALL | wx.CENTER | wx.EXPAND,
                       border=5)
        main_sizer.Add(button2, 0, wx.ALL, 5)
        self.SetSizer(main_sizer)

class MyFrame(wx.Frame):

    def __init__(self):
        super().__init__(None, title='Hello World')
        panel = MyPanel(self)
        self.Show()

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    app.MainLoop()

In this example, you create a wx.BoxSizer. A wx.BoxSizer can be set to add widgets horizontally (left-to-right) or vertically (top-to-bottom). For your code, you set the sizer to add widgets horizontally by using the wx.HORIZONTAL constant. To add a widget to a sizer, you use the Add() method.

The Add() method takes up to five arguments:

  • window – the widget to add
  • proportion – tells wxPython if the widget can change its size in the same orientation as the sizer
  • flag – one or more flags that affect the sizer’s behavior
  • border – the border width, in pixels
  • userData – allows adding an extra object to the sizer item, which is used for subclasses of sizers.

The first button that you add to the sizer is set to a proportion of 1, which will make it expand to fill as much space in the sizer as it can. You also give it three flags:

  • wx.ALL – add a border on all sides
  • wx.CENTER – center the widget within the sizer
  • wx.EXPAND – the item will be expanded as much as possible while also maintaining its aspect ratio

Finally, you add a border of five pixels. These pixels are added to the top, bottom, left, and right of the widget because you set the wx.ALL flag.

The second button has a proportion of 0, which means it wont expand at all. Then you tell it to add a five pixel border all around it as well. To apply the sizer to the panel, you need to call the panel’s SetSizer() method.

When you run this code, you will see the following applications:

Buttons in SizersButtons in Sizers

You can see how the various flags have affected the appearance of the buttons. Note that on MacOS, wx.Button cannot be stretched, so if you want to do that on a Mac, you would need to use a generic button from wx.lib.buttons instead. Generic buttons are usually made with Python and do not wrap the native widget.

Now let’s move on and learn how events work!

How to Add Events

So far you have created a couple of neat little applications with buttons, but the buttons don’t do anything when you click on them. Why is that? Well, when you are writing a GUI application, you need to tell it what to do when something happens. That “something” that happens is known as an event.

To hook an event to a widget, you will need to use the Bind() method. Some widgets have multiple events that can be bound to them while others have only one or two. The wx.Button can be bound to wx.EVT_BUTTON only.

Let’s copy the code from the previous example and paste it into a new file named button_events.py. Then update it to add events like this:

# button_events.py

import wx

class MyPanel(wx.Panel):

    def __init__(self, parent):
        super().__init__(parent)

        button = wx.Button(self, label='Press Me')
        button.Bind(wx.EVT_BUTTON, self.on_button1)
        button2 = wx.Button(self, label='Second button')
        button2.Bind(wx.EVT_BUTTON, self.on_button2)

        main_sizer = wx.BoxSizer(wx.HORIZONTAL)
        main_sizer.Add(button, proportion=1,
                       flag=wx.ALL | wx.CENTER | wx.EXPAND,
                       border=5)
        main_sizer.Add(button2, 0, wx.ALL, 5)
        self.SetSizer(main_sizer)

    def on_button1(self, event):
        print('You clicked the first button')

    def on_button2(self, event):
        print('You clicked the second button')

class MyFrame(wx.Frame):

    def __init__(self):
        super().__init__(None, title='Hello World')
        panel = MyPanel(self)
        self.Show()

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    app.MainLoop()

Here you call Bind() for each of the buttons in turn. You bind the button to wx.EVT_BUTTON, which will fire when the user presses a button. The second argument to Bind() is the method that should be called when you click the button.

If you run this code, the GUI will still look the same. However, when you press the buttons, you should see different messages printed to stdout (i.e. your terminal or console window). Give it a try and see how it works.

Now let’s go ahead and write a simple application!

How to Create an Application

The first step in creating an application is to come up with an idea. You could try to copy something simple like Microsoft Paint or Notepad. You will quickly find that they aren’t so easy to emulate as you would think, though! So instead, you will create a simple application that can load and display a photo.

When it comes to creating a GUI application, it is a good idea to think about what it will look like. If you enjoy working with pencil and paper, you could draw a sketch of what your application will look like. There are many software applications you can use to draw with or create simple mock-ups. To simulate a Sizer, you can draw a box.

Here is a mockup of what the finished application should look like:

Image Viewer MockupImage Viewer Mockup

Now you have a goal in mind. This allows you to think about how you might lay out the widgets. Go ahead and create a new file named image_viewer.py and add the following code to it:

# image_viewer.py

import wx

class ImagePanel(wx.Panel):
    
    def __init__(self, parent, image_size):
        super().__init__(parent)
        
        img = wx.Image(*image_size)
        self.image_ctrl = wx.StaticBitmap(self, 
                                          bitmap=wx.Bitmap(img))
        browse_btn = wx.Button(self, label='Browse')
        
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
        main_sizer.Add(browse_btn)
        self.SetSizer(main_sizer)
        main_sizer.Fit(parent)
        self.Layout()

class MainFrame(wx.Frame):
    
    def __init__(self):
        super().__init__(None, title='Image Viewer')
        panel = ImagePanel(self, image_size=(240,240))
        self.Show()

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MainFrame()
    app.MainLoop()

Here you create a new class named ImagePanel() that will hold all your widgets. Inside it, you have a wx.Image, which you will use to hold the photo in memory in an object that wxPython can work with. To display that photo to the user, you use wx.StaticBitmap. The other widget you need is the familiar wx.Button, which you will use to browse to the photo to load.

The rest of the code lays out the widgets using a vertically oriented wx.BoxSizer. You use the sizer’s Fit() method to try to make the frame “fit” the widgets. What that means is that you want the application to not have a lot of white space around the widgets.

When you run this code, you will end up with the following user interface:

Initial Image Viewer GUIInitial Image Viewer GUI

That looks almost right. It looks like you forgot to add the text entry widget to the right of the browse button, but that’s okay. The objective was to try and get a close approximation to what the application would look like in the end, and this looks pretty good. Of course, none of the widgets actually do anything yet.

Your next step is to update the code so it works. Copy the code from the previous example and make a new file named image_viewer_working.py. There will be significant updates to the code, which you will learn about soon. But first, here is the full change in its entirety:

# image_viewer_working.py

import wx

class ImagePanel(wx.Panel):

    def __init__(self, parent, image_size):
        super().__init__(parent)
        self.max_size = 240

        img = wx.Image(*image_size)
        self.image_ctrl = wx.StaticBitmap(self, 
                                          bitmap=wx.Bitmap(img))

        browse_btn = wx.Button(self, label='Browse')
        browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)

        self.photo_txt = wx.TextCtrl(self, size=(200, -1))

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        hsizer = wx.BoxSizer(wx.HORIZONTAL)

        main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
        hsizer.Add(browse_btn, 0, wx.ALL, 5)
        hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
        main_sizer.Add(hsizer, 0, wx.ALL, 5)

        self.SetSizer(main_sizer)
        main_sizer.Fit(parent)
        self.Layout()

    def on_browse(self, event):
        """
        Browse for an image file
        @param event: The event object
        """
        wildcard = "JPEG files (*.jpg)|*.jpg"
        with wx.FileDialog(None, "Choose a file",
                           wildcard=wildcard,
                           style=wx.ID_OPEN) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                self.photo_txt.SetValue(dialog.GetPath())
                self.load_image()
        
    def load_image(self):
        """
        Load the image and display it to the user
        """
        filepath = self.photo_txt.GetValue()
        img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
        
        # scale the image, preserving the aspect ratio
        W = img.GetWidth()
        H = img.GetHeight()
        if W > H:
            NewW = self.max_size
            NewH = self.max_size * H / W
        else:
            NewH = self.max_size
            NewW = self.max_size * W / H
        img = img.Scale(NewW,NewH)
        
        self.image_ctrl.SetBitmap(wx.Bitmap(img))
        self.Refresh()

class MainFrame(wx.Frame):

    def __init__(self):
        super().__init__(None, title='Image Viewer')
        panel = ImagePanel(self, image_size=(240,240))
        self.Show()

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MainFrame()
    app.MainLoop()

This change is pretty long. To make things easier, you will go over each change in its own little chunk. The changes all occurred in the ImagePanel class, so you will go over the changes in each of the methods in turn, starting with the constructor below:

def __init__(self, parent, image_size):
    super().__init__(parent)
    self.max_size = 240

    img = wx.Image(*image_size)
    self.image_ctrl = wx.StaticBitmap(self, 
                                      bitmap=wx.Bitmap(img))

    browse_btn = wx.Button(self, label='Browse')
    browse_btn.Bind(wx.EVT_BUTTON, self.on_browse)

    self.photo_txt = wx.TextCtrl(self, size=(200, -1))

    main_sizer = wx.BoxSizer(wx.VERTICAL)
    hsizer = wx.BoxSizer(wx.HORIZONTAL)

    main_sizer.Add(self.image_ctrl, 0, wx.ALL, 5)
    hsizer.Add(browse_btn, 0, wx.ALL, 5)
    hsizer.Add(self.photo_txt, 0, wx.ALL, 5)
    main_sizer.Add(hsizer, 0, wx.ALL, 5)

    self.SetSizer(main_sizer)
    main_sizer.Fit(parent)
    self.Layout()

There are a few minor changes here. The first one is that you added a max_size for the image. Then you hooked up an event to the the browse button. This button will now call on_browse() when it is clicked.

The next change is that you added a new widget, a wx.TextCtrl to be precise. You stored a reference to that widget in self.photo_txt, which will allow you to extract the path to the photo later.

The final change is that you now have two sizers. One is horizontal and the other remains vertical. The horizontal sizer is for holding the browse button and your new text control widgets. This allows your to place them next to each other, left-to-right. Then you add the horizontal sizer itself to the vertical main_sizer.

Now let’s see how on_browse() works:

def on_browse(self, event):
    """
    Browse for an image file
    @param event: The event object
    """
    wildcard = "JPEG files (*.jpg)|*.jpg"
    with wx.FileDialog(None, "Choose a file",
                       wildcard=wildcard,
                       style=wx.ID_OPEN) as dialog:
        if dialog.ShowModal() == wx.ID_OK:
            self.photo_txt.SetValue(dialog.GetPath())
            self.load_image()

Here you create a wildcard which is used by the wx.FileDialog to filter out all the other files types except the JPEG format. Next, you create the wx.FileDialog. When you do that, you set its parent to None and give it a simple title. You also set the wildcard and the style. style is an open file dialog instead of a save file dialog.

Then you show your dialog modally. What that means is that the dialog will appear over your main application and prevent you from interacting with the main application until you have accepted or dismissed the file dialog. If the user presses the OK button, then you will use GetPath() to get the path of the selected file and set the text control to that path. This effectively saves off the photo’s path so you can use it later.

Lastly, you call load_image() which will load the image into wxPython and attempt to show it. You can find out how by reading the following code:

def load_image(self):
    """
    Load the image and display it to the user
    """
    filepath = self.photo_txt.GetValue()
    img = wx.Image(filepath, wx.BITMAP_TYPE_ANY)
    
    # scale the image, preserving the aspect ratio
    W = img.GetWidth()
    H = img.GetHeight()
    if W > H:
        NewW = self.max_size
        NewH = self.max_size * H / W
    else:
        NewH = self.max_size
        NewW = self.max_size * W / H
    img = img.Scale(NewW,NewH)
    
    self.image_ctrl.SetBitmap(wx.Bitmap(img))
    self.Refresh()

The first step in this method is to extract the filepath from the text control widget. Then you pass that path along to a new instance of wx.Image. This will load the image into wxPython for you. Next, you get the width and height from the wx.Image object and use the max_size value to resize the image while maintaining its aspect ratio. You do this for two reasons. The first is because if you don’t, the image will get stretched out or warped. The second is that most images at full resolution won’t fit on-screen, so they need to be resized.

Once you have the new width and height, you Scale() the image down appropriately. Then you call your wx.StaticBitmap control’s SetBitmap() method to update it to the new image that you loaded. Finally, you call Refresh(), which will force the bitmap widget to redraw with the new image in it.

Here it is with a butterfly photo loaded in it:

Viewing an Image in wxPythonViewing an Image in wxPython

Now you have a fully-functional application that can load JPEG photos. You can update the application to load other image types if you’d like. The wxPython toolkit uses Pillow, so it will load the same types of image file types that Pillow itself can load.

Wrapping Up

The wxPython toolkit is extremely versatile. It comes with many, many widgets built-in and also includes a wonderful demo package. The demo package will help you learn how to use the widgets in your own code. You are only limited by your imagination.

In this chapter, you learned about the following topics:

  • Learning About Event Loops
  • How to Create Widgets
  • How to Lay Out Your Application
  • How to Add Events
  • How to Create an Application

You can take the code and the concepts in this code and add new features or create brand new applications. If you need ideas, you can check out some of the applications on your own computer or phone. You can also check out my book, Creating GUI Applications with wxPython, which has lots of fun little applications you can create and expand upon.

The post Python 101 – How to Create a Graphical User Interface appeared first on Mouse Vs Python.



from Planet Python
via read more

Will McGugan: Why I'm working on Open Source full time

I recently came to a decision which will have a big impact on my open source work. In particular Rich and Textual, but also pyfilesystem and lomond. For the foreseeable future, possibly up to a year, I'll be working on them essentially full time.

Rich is a very popular project now, with over 29K stars on Github. It has near 100% coverage and a stable API, but no codebase is ever really finished so there will be on-going work. Textual is Rich's sister project which is brand new and under active development, but already has 4.8K stars. It is also a much larger project than Rich. To do Textual justice I'm going to need to put in some serious time over and above what I could realistically do for a hobby project.

© 2021 Will McGugan

Some of the applications in the Textual examples directory

The end-goal with Textual is to make it the best way to create applications in the terminal (with Python or any other language). I want to do this by borrowing the best techniques from the web world which have been the intense focus of development for over a decade, but have rarely been applied to the terminal. I would also like to push the boundaries of what you would typically imagine a terminal application to be capable of. Terminals these days use video-game technology to support 16.7 million colors and can push updates at 60 frames per second or higher. I want to see what we can build if we allow ourselves to dip in to that power.

As much as I love flashy effects in the terminal, my main motivation with Textual is to make it easier to build Text User Interfaces (TUIs). The lowest common denominator for a (human) interface would be a command line interface. Python is not short of ways of adding a CLI (I like Typer), but what if it was at least as easy (or easier) to build a TUI? Maybe apps would be TUI first, or have --tui switch if you want a more discoverable way of working with an application.

In addition to working on Rich and Textual, I would also like to contribute to open source in other ways. One way is to offer code reviews to open source projects, with a particular focus on API design. Additionally, since my time will be my own I can contribute PRs to other projects, which I am looking forward to doing!

While I'm doing this I will have no income. Now I'm too old and too risk averse to do this without having put some savings aside, but I am also hoping to delay the inevitable return to a day job with Github Sponsors. I signed up a while ago and had been donating it to Bowel Cancer UK, but now it could help me pay some bills. If any of my work has made your life easier, or you want to support development of Rich and Textual, consider sponsoring me.

Full disclosure though, my motivation for this is more mutual that selfless. I think that there are commercial applications of Textual down the line, which may become a business. Textual itself will of course always be free and open source forever.

If you would like to follow my progress on Textual (I post regular updates), follow @willmcgugan on Twitter.

Before I go, here are a couple of recent updates to Textual:

Update 9

This examples demonstrates the easing functions borrowed from CSS.

Update 8

This example shows a tree control linked to a scroll view containing syntax highlighted code.



from Planet Python
via read more

Tuesday, September 28, 2021

Quansight Labs Blog: Low-code contributions through GitHub

Low-code contributions through GitHub

Healthy, inclusive communities are critical to impactful open source projects. A challenge for established projects is that the history and implicit technical debt increase the barrier to contribute to significant portions of code base. The literacy of large code bases happens over time through incremental contributions, and we'll discuss a format that can help people begin this journey.

At Quansight Labs, we are motivated to provide opportunities for new contributors to experience open source community work regardless of their software literacy. Community workshops are a common format for onboarding, but sometimes the outcome can be less than satisfactory for participants and organizers. In these workshops, there are implicit challenges that need to be overcome to contribute to projects' revision history like Git or setting up development environments.

Our goal with the following low-code workshop is to offer a way for folks to join a project's contributors list without the technical overhead. To achieve this we'll discuss a format that relies solely on the GitHub web interface.

Read more… (5 min remaining to read)



from Planet Python
via read more

TestDriven.io: Working with Static and Media Files in Django

This article looks at how to work with static and media files in a Django project, locally and in production. from Planet Python via read...