skip to navigation
skip to content

Planet Python

Last update: March 21, 2019 10:47 AM UTC

March 20, 2019


Mike Driscoll

Book Review: Mission Python

A couple of months ago, No Starch Press asked me if I would be interested in reading one of their new books called Mission Python: Code a Space Adventure Game! by Sean McManus. I enjoy reading new tech books, but it’s hard to work them in when I’ve been so busy this past year. However one of my resolutions for 2019 is to read through my backlog of tech books, so I decided to tackle this one next!


Quick Review

  • Why I picked it up: Originally, the publisher asked me check the book out, but I was also interested because I think game programming is intriguing
  • Why I finished it: I mostly skimmed this book, but it’s definitely worth a read to see how to put a game together
  • I’d give it to: Developers that want to learn how quickly and easily it is to write a 2D game in Python

  • Book Formats

    You can get this book as a paperback, PDF, Mobi, or ePub.


    Book Contents

    This book contains 12 chapters and 3 appendices across 280 pages. The code in this book is for Windows or Raspberry Pi. You will also need Python 3 for this book as it uses PyGame Zero, which requires Python 3.


    Full Review

    Mission Python attempts to teach you the Python programming language while also building a 2D video game using PyGame Zero. The introduction helpfully explains how to install Python and the dependencies needed for the game on Windows and Raspberry Pi. If you happen to be on Linux or Mac, you will have to figure out how to install it on your own.

    The first chapter of the book instructs the reader on using Python’s IDLE application for developing your code. The rest of the chapter introduces you to writing the some of the the game. Basically you create the background for the game and learn about blitting. You also learn how to move a character in the game using your keyboard.

    Chapter 2 digs into Python lists and how you can use them in conjunction with your game. The author uses list building and accessing elements within a list to help the reader create space related checklists and eventually a map of sorts. It’s a rather creative way to integrate Python lists and a video game at the same time.

    The next step in the reader’s journey is learning about Python loops in chapter 3. Loops are used for printing the “map” to the screen. The map is basically a matrix of numbers. After describing how to do nested loops, the author uses that newfound knowledge to help the user create a room image using PyGame Zero’s drawing abilities.

    For chapter 4, the author teaches the reader how to create the map and the automatic map maker too. Here you will learn how to use PyGame Zero to draw the map onscreen and debug the code when you inevitably run into issues.

    Chapters 5 and 6 are about the space station’s equipment and focus on Python dictionaries. Here the reader will learn how to mix data types in Python, such as adding lists to dictionaries. You will also be learning how to load scenery into the rooms in your game.

    The goal of chapter 7 is to teach you how to move your sprites about in the game. For this task, the reader learns how to hook up the keyboard to the game and the different versions of the sprites you will need to make movement look natural.

    The rest of the book builds up various parts of the game itself. You will be learning how to use functions along the way and there are exercises spread throughout the book. Most of the rest of the book focuses on PyGame specific functions and methods and how to use them effectively.

    This book seems well organized and pretty well written. I personally find the chapter titles a bit confusing as you can’t really tell from the titles alone what the chapter is actually about. The section names are sometimes written in an obtuse manner as well. However the content of the book is interesting and it’s fun to learn how to write a game in Python. I would give this book to someone who would like to learn all the moving parts of writing a game in Python. You won’t be learning game theory, but it’s still a good introduction to game development with nice, small chunks of code.

    Mission Python

    by Sean McManus

    Amazon, No Starch


    Other Book Reviews

    March 20, 2019 10:45 PM UTC


    Continuum Analytics Blog

    Announcing Public Anaconda Package Download Data

    I’m very happy to announce that starting today, we will be publishing summarized download data for all conda packages served in the Anaconda Distribution, as well as the popular conda-forge and bioconda channels.  The dataset…

    The post Announcing Public Anaconda Package Download Data appeared first on Anaconda.

    March 20, 2019 06:24 PM UTC


    Python Data

    Comparing Machine Learning Methods

    When working with data and modeling, its sometimes hard to determine what model you should use for a particular modeling project.  A quick way to find an algorithm that might work better than others is to run through an algorithm comparison loop to see how various models work against your data. In this post, I’ll be comparing machine learning methods using a few different sklearn algorithms.  As always, you can find a jupyter notebook for this article on my github here.

    I’ve used Jason Brownlee’s article from 2016 as the basis for this article…I wanted to expand a bit on what he did as well as use a different dataset. In this article, we’ll be using the Indian Liver Disease dataset (found here).

    From the dataset page:

    This data set contains 416 liver patient records and 167 non liver patient records collected from North East of Andhra Pradesh, India. The “Dataset” column is a class label used to divide groups into liver patient (liver disease) or not (no disease). This data set contains 441 male patient records and 142 female patient records.

    Let’s get started by setting up our imports that we’ll use.

    import pandas as pd
    import matplotlib.pyplot as plt
    plt.rcParams["figure.figsize"] = (20,10)
    
    from sklearn import model_selection
    from sklearn.linear_model import LogisticRegression
    from sklearn.svm import SVC
    from sklearn.neighbors import KNeighborsClassifier
    from sklearn.tree import DecisionTreeClassifier
    from sklearn.naive_bayes import GaussianNB
    from sklearn.discriminant_analysis import LinearDiscriminantAnalysis

    Next, we’ll read in the data from the CSV file located in the local directory.

    #read in the data
    data = pd.read_csv('indian_liver_patient.csv')

    If you do a head() of the dataframe, you’ll get a good feeling for the dataset.

    Indian Liver Disease Data

    We’ll use all columns except Gender for this tutorial. We could use gender by converting the gender to a numeric value (e.g., 0 for Male, 1 for Female) but for the purposes of this post, we’ll just skip this column.

    data_to_use = data
    del data_to_use['Gender']
    data_to_use.dropna(inplace=True)

    The ‘Dataset’ column is the value we are trying to predict…whether the user has liver disease or not so we’ll that as our “Y” and the other columns for our “X” array.

    values = data_to_use.values
    
    Y = values[:,9]
    X = values[:,0:9]

    Before we run our machine learning models, we need to set a random number to use to seed them. This can be any random number that you’d like it to be. Some people like to use a random number generator but for the purposes of this, I’ll just set it to 12 (it could just as easily be 1 or 3 or 1023 or any other number).

    random_seed = 12

    Now we need to set up our models that we’ll be testing out. We’ll set up a list of the models and give them each a name. Additionally, I’m going to set up the blank arrays/lists for the outcomes and the names of the models to use for comparison.

    outcome = []
    model_names = []
    models = [('LogReg', LogisticRegression()), 
              ('SVM', SVC()), 
              ('DecTree', DecisionTreeClassifier()),
              ('KNN', KNeighborsClassifier()),
              ('LinDisc', LinearDiscriminantAnalysis()),
              ('GaussianNB', GaussianNB())]

    We are going to use a k-fold validation to evaluate each algorithm and will run through each model with a for loop, running the analysis and then storing the outcomes into the lists we created above. We’ll use a 10-fold cross validation.

    for model_name, model in models:
        k_fold_validation = model_selection.KFold(n_splits=10, random_state=random_seed)
        results = model_selection.cross_val_score(model, X, Y, cv=k_fold_validation, scoring='accuracy')
        outcome.append(results)
        model_names.append(model_name)
        output_message = "%s| Mean=%f STD=%f" % (model_name, results.mean(), results.std())
        print(output_message)

    The output from this loop is:

    LogReg| Mean=0.718633 STD=0.058744
    SVM| Mean=0.715124 STD=0.058962
    DecTree| Mean=0.637568 STD=0.108805
    KNN| Mean=0.651301 STD=0.079872
    LinDisc| Mean=0.716878 STD=0.050734
    GaussianNB| Mean=0.554719 STD=0.081961

    From the above, it looks like the Logistic Regression, Support Vector Machine and Linear Discrimination Analysis methods are providing the best results (based on the ‘mean’ values). Taking Jason’s lead, we can take a look at a box plot to see what the accuracy is for each cross validation fold, we can see just how good each does relative to each other and their means.

    fig = plt.figure()
    fig.suptitle('Machine Learning Model Comparison')
    ax = fig.add_subplot(111)
    plt.boxplot(outcome)
    ax.set_xticklabels(model_names)
    plt.show()

    Machine Learning Comparison

    From the box plot, it is easy to see the three mentioned (Logistic Regression, Support Vector Machine and Linear Discrimination Analysis) are providing the better accuracies. From this outcome, we can then take this data and start working with these three models to see how we might be able to optimize the modeling process to see if one model works a bit better than others.

    The post Comparing Machine Learning Methods appeared first on Python Data.

    March 20, 2019 05:35 PM UTC


    Anarcat

    Securing registration email

    I've been running my own email server basically forever. Recently, I've been thinking about possible attack vectors against my personal email. There's of course a lot of private information in that email address, and if someone manages to compromise my email account, they will see a lot of personal information. That's somewhat worrisome, but there are possibly more serious problems to worry about.

    TL;DR: if you can, create a second email address to register on websites and use stronger protections on that account from your regular mail.

    Hacking accounts through email

    Strangely what keeps me up at night is more what kind of damage an attacker could do to other accounts I hold with that email address. Because basically every online service is backed by an email address, if someone controls my email address, they can do a password reset on every account I have online. In fact, some authentication systems just gave up on passwords algother and use the email system itself for authentication, essentially using the "password reset" feature as the authentication mechanism.

    Some services have protections against this: for example, GitHub require a 2FA token when doing certain changes which the attacker hopefully wouldn't have (although phishing attacks have been getting better at bypassing those protections). Other services will warn you about the password change which might be useful, except the warning is usually sent... to the hacked email address, which doesn't help at all.

    The solution: a separate mailbox

    I had been using an extension (anarcat+register@example.com) to store registration mail in a separate folder for a while already. This allows me to bypass greylisting on the email address, for one. Greylisting is really annoying when you register on a service or do a password reset... The extension also allows me to sort those annoying emails in a separate folder automatically with a simple Sieve rule.

    More recently, I have been forced to use a completely different email alias (register@example.com) on some services that dislike having plus signs (+) in email address, even though they are perfectly valid. That got me thinking about the security problem again: if I have a different alias why not make it a completely separate account and harden that against intrusion. With a separate account, I could enforce things like SSH-only access or 2FA that would be inconvenient for my main email address when I travel, because I sometimes log into webmail for example. Because I don't frequently need access to registration mail, it seemed like a good tradeoff.

    So I created a second account, with a locked password and SSH-only authentication. That way the only way someone can compromise my "registration email" is by hacking my physical machine or the server directly, not by just bruteforcing a password.

    Now of course I need to figure out which sites I'm registered on with a "non-registration" email (anarcat@example.com): before I thought of using the register@ alias, I sometimes used my normal address instead. So I'll have to track those down and reset those. But it seems I already blocked a large attack surface with a very simple change and that feels quite satisfying.

    Implementation details

    Using syncmaildir (SMD) to sync my email, the change was fairly simple. First I need to create a second SMD profile:

    if [ $(hostname) = "marcos" ]; then
        exit 1
    fi
    
    SERVERNAME=smd-server-register
    CLIENTNAME=$(hostname)-register
    MAILBOX_LOCAL=Maildir/.register/
    MAILBOX_REMOTE=Maildir
    TRANSLATOR_LR="smd-translate -m move -d LR register"
    TRANSLATOR_RL="smd-translate -m move -d RL register"
    EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
    

    Very similar to the normal profile, except mails get stored in the already existing Maildir/.register/ and different SSH profile and translation rules are used. The new SSH profile is basically identical to the previous one:

    # wrapper for smd
    Host smd-server-register
        Hostname imap.anarc.at
        BatchMode yes
        Compression yes
        User register
        IdentitiesOnly yes
        IdentityFile ~/.ssh/id_ed25519_smd
    

    Then we need to ignore the register folder in the normal configuration:

    diff --git a/.smd/config.default b/.smd/config.default
    index c42e3d0..74a8b54 100644
    --- a/.smd/config.default
    +++ b/.smd/config.default
    @@ -59,7 +59,7 @@ TRANSLATOR_RL="smd-translate -m move -d RL default"
     # EXCLUDE_LOCAL="Mail/spam Mail/trash"
     # EXCLUDE_REMOTE="OtherMail/with%20spaces"
     #EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
    -EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
    +EXCLUDE="Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/* Maildir/.register/*"
     #EXCLUDE_LOCAL="$MAILBOX_LOCAL/.notmuch/hooks/* $MAILBOX_LOCAL/.notmuch/xapian/*"
     #EXCLUDE_REMOTE="$MAILBOX_REMOTE/.notmuch/hooks/* $MAILBOX_REMOTE/.notmuch/xapian/*"
     #EXCLUDE_REMOTE="Maildir/Koumbit Maildir/Koumbit* Maildir/Koumbit/* Maildir/Koumbit.INBOX.Archives/ Maildir/Koumbit.INBOX.Archives.2012/ Maildir/.notmuch/hooks/* Maildir/.notmuch/xapian/*"
    

    And finally we add the new profile to the systemd services:

    diff --git a/.config/systemd/user/smd-pull.service b/.config/systemd/user/smd-pull.service
    index a841306..498391d 100644
    --- a/.config/systemd/user/smd-pull.service
    +++ b/.config/systemd/user/smd-pull.service
    @@ -8,6 +8,7 @@ ConditionHost=!marcos
     Type=oneshot
     # --show-tags gives email counts
     ExecStart=/usr/bin/smd-pull --show-tags
    +ExecStart=/usr/bin/smd-pull --show-tags register
    
     [Install]
     WantedBy=multi-user.target
    diff --git a/.config/systemd/user/smd-push.service b/.config/systemd/user/smd-push.service
    index 10d53c7..caa588e 100644
    --- a/.config/systemd/user/smd-push.service
    +++ b/.config/systemd/user/smd-push.service
    @@ -8,6 +8,7 @@ ConditionHost=!marcos
     Type=oneshot
     # --show-tags gives email counts
     ExecStart=/usr/bin/smd-push --show-tags
    +ExecStart=/usr/bin/smd-push --show-tags register
    
     [Install]
     WantedBy=multi-user.target
    

    That's about it on the client side. On the server, the user is created with a locked password the mailbox moved over:

    adduser --disabled-password register
    mv ~anarcat/Maildir/.register/ ~register/Maildir/
    chown -R register:register Maildir/
    

    The SSH authentication key is added to .ssh/authorized_keys, and the alias is reversed:

    --- a/aliases
    +++ b/aliases
    @@ -24,7 +24,7 @@ spamtrap: anarcat
     spampd: anarcat
     junk: anarcat
     devnull: /dev/null
    -register: anarcat+register
    +anarcat+register: register
    
     # various sandboxes
     anarcat-irc: anarcat
    

    ... and the email is also added to /etc/postgrey/whitelist_recipients.

    That's it: I now have a hardened email service! Of course there are other ways to harden an email address. On-disk encryption comes to mind but that only works with password-based authentication from what I understand, which is something I want to avoid to remove bruteforce attacks.

    Your advice and comments are of course very welcome, as usual

    March 20, 2019 03:28 PM UTC


    PyCharm

    PyCharm 2019.1 RC 2

    New in PyCharm 2019.1: completely redesigned Jupyter Notebooks, improved HTML & CSS quick documentation, custom themes, and more. Get the release candidate from our website

    New in PyCharm

    Custom Themes

    UI Themes

    We’ve now added official support for theme plugins, so be sure to check out the themes available in the Marketplace to see if there’s one you like. In addition to the popular third party Material Theme UI plugin, our own UI team has now published several plugins. For example, the Cyan Light theme:

    CyanLight

    If you don’t like any of the available UI themes, you can also make your own. Read more about creating UI themes on the IntelliJ blog.

    Redesigned Database Connection Flow

    DB Flow

    PyCharm Professional Edition bundles the advanced database tools from JetBrains DataGrip, a tool that can manage databases from all major vendors. DataGrip has redesigned the flow for connecting to a database, and this is now also available in PyCharm.

    If you’re working on a database-connected application, be sure to configure your database settings in PyCharm. With the database connected, you get schema-aware SQL completion in Python code, and you can quickly run a query embedded in Python code straight from the editor.

    SQL

    Further Improvements

    Interested?

    Download the RC from our website. Alternatively, you can use the JetBrains Toolbox App to stay up to date.

    If you’re on Ubuntu 16.04 or later, you can use snap to get PyCharm RC versions, and stay up to date. You can find the installation instructions on our website.

    The release candidate (RC) is not an early access program (EAP) build, and does not bundle an EAP license. If you get PyCharm Professional Edition RC, you will either need a currently active PyCharm subscription, or you will receive a 30-day free trial.

    March 20, 2019 02:57 PM UTC


    Abhijeet Pal

    How To Create A ‘Hello, World!’ Application With Django

    Django is a high-level full stack open source web framework written in Python, that encourages rapid development and clean, pragmatic design. Django comes with lots of advance functionalities baked in which saves developers a lot of time. The simplicity Django offers lets developers focus more on writing the app instead of rewriting the same wheel. Since it’s release in 2003 Django has proven to be the most productive framework for Python developers to know more about Django read: Django – Web Framework For Perfectionists

    In this article, we will create the traditional “Hello, World!” app, which will basically display the string ‘Hello, world!’ in the browser. This might be your first Django app so pay close attention to the core principles of Django which we will discuss later in the article.

    Creating A Virtual Environment

    Though this is an optional step yet it is highly recommended to use virtual environments in your projects, to know why are virtual environments so important read: How To A Create Virtual Environment for Python

    In a nutshell, virtual environment lets you have an isolated space on your computer for different Python projects, ensuring that each of your projects can have its own set of dependencies and modules that won’t disrupt any of your other projects.

    Let’s kick off by creating a virtual environment for our hello world project.

    For Windows

    cd Desktop
    virtualenv django
    cd django
    Scripts\activate.bat

    For Mac and Unix

    mkdir django
    cd django
    python3 -m venv myenv
    source django/bin/activate

    Now you should see (django) prefixed in your terminal, which indicates that the virtual environment is successfully activated, if not then go through the guide again.

    Installing Django In The Virtual Environment

    Now, we need to Install Django on our virtual environment.

    pip install Django

    This will install the latest version of Django in our virtual Environment. To know more about Django installation read: How To Install Django

    Creating A Django Project

    Moving on, now time to build the Hello world project, this is a basic Django project. First, create a directory in your desktop named, hello_world and navigate into it.

    cd Desktop
    mkdir hello_world 
    cd hello_world

    Next, create a Django Project:

    django-admin startproject hello_world_project

    Executing this will invoke the django-admin.py script which will set up a new Django project instance name hello_world_project in the hello_world directory.

    hello_world_project/
       manage.py
       hello_world_project/
          __init__.py
          settings.py
          urls.py
          wsgi.py

    To know about these files and the project structure we highly recommend to read: Starting A Django Project

    Nevertheless briefly going over the files,

    manage.py – Command line utility lets you interact with your Django project.

    __init__.py –  a blank Python script whose presence indicates to the Python interpreter that the directory is a Python package.

    settings.py – Contains the configuration settings for the Django project.

    urls.py – Contains URL patterns for the Django project.

    wsgi.py – Contains WSGI configuration properties for the Django project.

    Now, let’s apply migrations and test our project. Navigate into the Base directory ( i.e. the outer directory ) and run these commands.

    cd hello_world_project
    python manage.py migrate
    python manage.py runserver

    This will start the Django’s built-in server now open your preferred browser and navigate to this address http://127.0.0.1:8000/ if everything went well you should see the default Django’s welcome page.

    Starting A Django Project

    Now press ctrl+c in the terminal window, to stop the server.

    Creating A Django App

    A Django project is a set of applications and configurations which combined make a full-fledged web application. Django apps are the sub-directories inside the Django project. The purpose of Django applications is to perform a particular task which in this case is to render ‘Hello, World!’.

    Make sure you are at the outer directory where manage.py is and run the following.

     python manage.py startapp my_app

    This will create another directory inside the project called my_app, now the project should look something like this.

    ├── db.sqlite3
    ├── hello_world_project
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   ├── wsgi.py
    ├── manage.py
    └── my_app
        ├── __init__.py
        ├── admin.py
        ├── apps.py
        ├── migrations
        │   └── __init__.py
        ├── models.py
        ├── tests.py
        └── views.py

    There are lots of new files in the apps which we haven’t seen before in the project,

    admin.py – File with admin definitions for the app – such definitions are needed to access model class instances from the Django admin

    apps.py – File with configuration parameters for the app.

    models.py – File with database definitions (i.e., model classes) for the app.

    tests.py – File with test definitions for the app.

    views.py – File with view definitions (i.e., controller methods) for the app.

    migrations – The directory that contains migrations applied to the app’s database definitions (i.e., model classes).

    Now we need to add this app into the Installed apps list in Django’s settings so that Django can know about the app. Open your preferred text editor and open the settings.py file and scroll to the INSTALLED_APPS section. There you should see the list of built-in Django apps.

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
    ]

    Add my_app below the preinstalled apps and save it. Note that user-defined apps should always be below the pre-installed apps because Django read the apps in the top to down fashion and our app may rely on the Django’s core apps.

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'my_app'
    ]

    Creating Web App

    Till now everything was about the configuration which is needed to be done for any web app, now it’s time to actually design the app. Suppose you were creating a hello world app without a framework you’d simply type Hello world into a text file, call it hello.html, and upload it to a directory on a web server somewhere.

    Notice in this process you’ve specified two key pieces of information about that web page: its contents (the string Hello world) and its URL (for example, http://www.example.com/hello.html).

    With Django, you specify those same two things, but in a different manner. The view function produces the contents of the page in the views.py file and the URL is specified in urls.py file.

    Let’s create our first view, open views.py file of my_app and add the below lines.

    from django.http import HttpResponse
    
    def index(request):
        return HttpResponse('Hello, World!')

    First, we imported the HttpResponse class from django.http module then we made a function that takes in a request and returns a HttpResponse object i.e. the string ‘Hello, World!’. Note that every view function must take atleast one parameter by convention called request.

    In order to see this view in our browser, we need to map this view in our URL configurations. Open the urls.py file of the main project. Which should look like this.

    from django.contrib import admin
    from django.urls import path
    
    urlpatterns = [
        path('admin/', admin.site.urls),
    ]

    Now we need to tell Django explicitly that we need to activate the view for a particular URL

    from django.contrib import admin
    from django.urls import path
    # imported views
    from my_app import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        # configured the url
        path('',views.index, name="homepage")
    ]
    

    First, we imported the views from my_app directory then in the URL patterns we added the path for the view which is the homepage hence blank string denoted with ' ' than we mapped this URL to our index view, and at last the optional argument name which we assign to homepage. This implies every request to the homepage should return the ‘Hello, world!’ string.

    Now let’s test out our app save the files open terminal and run the development server.

    python manage.py runserver

    Now visit http://127.0.0.1:8000/ you should see Hello, World! written there.

    Try adding random paths after the URL like http://127.0.0.1:8000/something this will return 404 pages because we haven’t mapped URLs for those pages.

    In this article, we went through the creation of the traditional ‘Hello, world!’ app with Django if you have any question regarding it feel free to ask in the comment section below.

    The post How To Create A ‘Hello, World!’ Application With Django appeared first on Django Central.

    March 20, 2019 02:53 PM UTC


    Trey Hunner

    Unique sentinel values, identity checks, and when to use object() instead of None

    Occasionally in Python (and in programming in general), you’ll need an object which can be uniquely identified. Sometimes this unique object represents a stop value or a skip value and sometimes it’s an initial value. But in each of these cases you want your object to stand out from the other objects you’re working with.

    When you need a unique value (a sentinel value maybe) None is often the value to reach for. But sometimes None isn’t enough: sometimes None is ambiguous.

    In this article we’ll talk about when None isn’t enough, I’ll show you how I create unique values when None doesn’t cut it, and we’ll see a few different uses for this technique.

    Initial values and default values

    Let’s re-implement a version of Python’s built-in min function.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    def min(iterable, default=None):
        """Imperfect re-implementation of Python's built-in min function."""
        minimum = None
        for item in iterable:
            if minimum is None or item < minimum:
                minimum = item
        if minimum is not None:
            return minimum
        elif default is not None:
            return default
        else:
            raise ValueError("Empty iterable")
    

    This min function, like the built-in one, returns the minimum value in the given iterable or raises an exception when an empty iterable is given unless a default value is specified (in which case the default is returned).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    >>> min([4, 3, 8, 7])
    3
    >>> min([9])
    9
    >>> min([])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in min
    ValueError: Empty iterable
    >>> min([], default=9)
    9
    >>> min([4, 3, 8, 7], default=9)
    3
    

    This behavior is somewhat similar to the built-in min function, except our code is buggy!

    There are two bugs here.

    First, an iterable containing a single None value will be treated as if it was an empty iterable:

    1
    2
    3
    4
    5
    6
    7
    
    >>> min([None], default=0)
    0
    >>> min([None])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 8, in min
    ValueError: Empty iterable
    

    Second, if we specify our default value as None this min function won’t accept it:

    1
    2
    3
    4
    5
    6
    7
    
    >>> min([], default='')
    ''
    >>> min([], default=None)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in min
    ValueError: Empty iterable
    

    Why is this happening?

    It’s all about None.

    Why is None a problem?

    The first bug in our code is related to the initial value for minimum and the second is related to the default value for our default argument. In both cases, we’re using None to represent an unspecified or un-initialized value.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    def min(iterable, default=None):
        """Imperfect re-implementation of Python's built-in min function."""
        minimum = None
        for item in iterable:
            if minimum is None or item < minimum:
                minimum = item
        if minimum is not None:
            return minimum
        elif default is not None:
            return default
        else:
            raise ValueError("Empty iterable")
    

    Using None is a problem in both cases because None is both a valid value for default and a valid value in our iterable.

    Python’s None value is useful for representing emptiness, but it isn’t magical, at least not any more magical than any other valid value.

    If we need a truly unique value for our default state, we need to invent our own.

    When None isn’t a valid input for your function, it’s perfectly fine to use it to represent a unique default or initial state. But None is often valid data, which means None is sometimes a poor choice for a unique initial state.

    We’ll fix both of our bugs by using object(): a somewhat common convention for creating a truly unique value in Python.

    First we’ll set minimum to a unique object:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    def min(iterable, default=None):
        """Imperfect re-implementation of Python's built-in min function."""
        initial = object()
        minimum = initial
        for item in iterable:
            if minimum is initial or item < minimum:
                minimum = item
        if minimum is not initial:
            return minimum
        elif default is not None:
            return default
        else:
            raise ValueError("Empty iterable")
    

    That initial variable holds our unique value so we can check for its presence later.

    This fixes the first bug:

    1
    2
    3
    4
    5
    6
    7
    
    >>> min([None], default=0)
    >>> min([None])
    >>> min([])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 13, in min
    ValueError: Empty iterable
    

    But not the second.

    To fix the second bug we need to use a different default value for our default argument (other than None).

    To do this, we’ll make a global “constant” (by convention) variable, INITIAL, outside our function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    INITIAL = object()
    
    
    def min(iterable, default=INITIAL):
        """Imperfect re-implementation of Python's built-in min function."""
        minimum = INITIAL
        for item in iterable:
            if minimum is INITIAL or item < minimum:
                minimum = item
        if minimum is not INITIAL:
            return minimum
        elif default is not INITIAL:
            return default
        else:
            raise ValueError("Empty iterable")
    

    Now our code works exactly how we’d hope it would:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    >>> min([None], default=0)
    >>> min([None])
    >>> min([], default=None)
    >>> min([], default='')
    ''
    >>> min([4, 3, 7, 8])
    3
    >>> min([4, 3, 7, 8], default=0)
    3
    >>> min([])
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 12, in min
    ValueError: Empty iterable
    

    That’s lovely… but what is this magical object() thing? Why does it work, how does it work, and when should we use it?

    What is object()?

    Every class in Python has a base class of object (in Python 3 that is… things were a bit weirder in Python 2).

    So object is a class:

    1
    2
    3
    4
    
    >>> object
    <class 'object'>
    >>> type(object)
    <class 'type'>
    

    When we call object we’re creating an “instance” of the object class, just as calling any other class (when given the correct arguments) will create instances of them:

    1
    2
    3
    4
    5
    6
    
    >>> set()
    set()
    >>> bytearray()
    bytearray(b'')
    >>> frozenset()
    frozenset()
    

    So we’re creating an instance of object. But… why?

    Well, an instance of object shouldn’t be seen as equal to any other object:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    >>> x = object()
    >>> y = object()
    >>> x == y
    False
    >>> x == 4
    False
    >>> x == None
    False
    >>> x == []
    False
    

    Except itself:

    1
    2
    3
    4
    
    >>> x = object()
    >>> z = x
    >>> x == z
    True
    

    Python’s None is similar, except that anyone can get access to this unique None object anywhere in their code by just typing None.

    1
    2
    3
    4
    5
    6
    7
    8
    
    >>> x = None
    >>> y = None
    >>> x == y
    True
    >>> x = object()
    >>> y = object()
    >>> x == y
    False
    

    We needed a placeholder value in our code. None is a lovely placeholder as long as we don’t need to worry about distinguishing between our None and their None.

    If None is valid data, it’s no longer just a placeholder. At that point, we need to start reaching for object() instead.

    Equality vs identity

    I noted that object() isn’t equal to anything else. But we weren’t actually checking for equality (using == or !=) in our function:

    Instead of == and !=, we used is and is not.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    INITIAL = object()
    
    
    def min(iterable, default=INITIAL):
        """Imperfect re-implementation of Python's built-in min function."""
        minimum = INITIAL
        for item in iterable:
            if minimum is INITIAL or item < minimum:
                minimum = item
        if minimum is not INITIAL:
            return minimum
        elif default is not INITIAL:
            return default
        else:
            raise ValueError("Empty iterable")
    

    While == and != are equality operators, is and is not are identity operators.

    Python’s is operator asks about the identity of an object: are the two objects on either side of the is operator actually the same exact object.

    We’re not just asking are they equal, but are they stored in the same place in memory and in fact refer to the same exact object.

    Two of the variables below (x and z) point to the same object:

    1
    2
    3
    
    >>> x = object()
    >>> y = object()
    >>> z = x
    

    So while y has a unique ID in memory, x and z do not:

    1
    2
    3
    4
    5
    6
    
    >>> id(x)
    140079600030400
    >>> id(y)
    140079561403808
    >>> id(z)
    140079600030400
    

    Which means x is identical to z:

    1
    2
    3
    4
    
    >>> x is y
    False
    >>> x is z
    True
    

    By default, Python’s == operator delegates to is. Meaning unless two variables point to the exact some object in memory, == will return False:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    >>> x = object()
    >>> y = object()
    >>> z = x
    >>> x == x
    True
    >>> x == y
    False
    >>> x == z
    True
    

    This is true by default… but many objects in Python overload the == operator to do much more useful things when we ask about equality.

    1
    2
    3
    4
    5
    6
    7
    8
    
    >>> 0 == 0.0
    True
    >>> [1, 2, 3] == [1, 2, 3]
    True
    >>> (1, 2) == (1, 3)
    False
    >>> {} == {}
    True
    

    Each object can customize the behavior of == to answer whatever question they’d like.

    Which means someone could make a class like this:

    1
    2
    3
    4
    
    >>> class AlwaysEqual:
    ...     def __eq__(self, other):
    ...         return True
    ...
    

    And suddenly our assumption about == with object() (or any other value) will fail us:

    1
    2
    3
    4
    5
    6
    
    >>> x = object()
    >>> y = AlwaysEqual()
    >>> x is y
    False
    >>> x == y
    True
    

    Use identity to compare unique objects

    The is operator, unlike ==, is not overloadable. Unlike with ==, there’s no way to control or change what happens when you say x is y.

    There’s a __eq__ method, but there’s no such thing as a __is__ method. Which means the is operator will never lie to you: it will always tell you whether two objects are one in the same.

    If we use is instead of ==, we could actually use any unique object to represent our unique INITIAL value.

    Even an empty list:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    INITIAL = []
    
    
    def min(iterable, default=INITIAL):
        """Imperfect re-implementation of Python's built-in min function."""
        minimum = INITIAL
        for item in iterable:
            if minimum is INITIAL or item < minimum:
                minimum = item
        if minimum is not INITIAL:
            return minimum
        elif default is not INITIAL:
            return default
        else:
            raise ValueError("Empty iterable")
    

    An empty list might seem problematic in the same way as None was: but they’re actually quite different.

    We don’t have any of the same issues as we did with None before:

    1
    2
    3
    4
    5
    6
    
    >>> min([[]], default=0)
    []
    >>> min([[]])
    []
    >>> min([], default=[])
    []
    

    The reason is that None is a singleton value. That means that whenever you say None in your Python code, you’re referencing the exact same None object every time.

    1
    2
    3
    4
    5
    6
    
    >>> x = None
    >>> y = None
    >>> x is y
    True
    >>> id(x), id(y)
    (94548887510464, 94548887510464)
    

    Whereas every empty list we make creates a brand new list object:

    1
    2
    3
    4
    5
    6
    
    >>> x = []
    >>> y = []
    >>> x is y
    False
    >>> id(x), id(y)
    (140079561624776, 140079598927432)
    

    So while two independent empty lists may be equal, they aren’t the same object:

    1
    2
    3
    4
    5
    6
    
    >>> x = []
    >>> y = []
    >>> x == y
    True
    >>> x is y
    False
    

    The objects that those x and y variables point to have the same value but are not actually the same object.

    None is a placeholder value

    Python’s None is lovely. None is a universal placeholder value. Need a placeholder? Great! Python has a great placeholder value and it’s called None!

    There are lots of places where Python itself actually uses None as a placeholder value also.

    If you pass no arguments to the string split method, that’s the same as passing a separator value of None:

    1
    2
    3
    4
    5
    
    >>> s = "hello world"
    >>> s.split()
    ['hello', 'world']
    >>> s.split(None)
    ['hello', 'world']
    

    If you pass in a key function of None to the sorted builtin, that’s the same as passing in no key function at all:

    1
    2
    3
    4
    
    >>> sorted(s, key=None)
    [' ', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
    >>> sorted(s)
    [' ', 'd', 'e', 'h', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
    

    Python loves using None as a placeholder because it’s often a pretty great placeholder value.

    The issue with None only appears if someone else could reasonably be using None as a non-placeholder input to our function. This is often the case when the caller of a function has a placeholder values (often None) in their inputs and the author of that function (that’s us) needs a separate unique placeholder.

    Using None to represent two different things at once is like having two identical-looking bookmarks in the same book: it’s confusing!

    Creating unique non-None placeholders: why object()?

    When we made that INITIAL value before, we were sort of inventing our own None-like object: an object that we could uniquely reference by using the is operator.

    That INITIAL object we made should be completely unique: it shouldn’t ever be seen in any arbitrary input that may be given to our function (unless someone made the strange decision to import INITIAL and reference it specifically).

    Why object() though? After all we could have used any unique object by creating an instance of pretty much any class:

    1
    2
    3
    4
    5
    
    >>> INITIAL = []
    >>> INITIAL == []
    True
    >>> INITIAL is []
    False
    

    Though it might have been even more clear to create our own class just for this purpose:

    1
    2
    3
    4
    
    class DummyClass:
        """Class that just creates unique objects."""
    
    INITIAL = DummyClass()
    

    But I’d argue that object() is the “right” thing to use here.

    Everyone knows what [] means, but object() is mysterious, which is actually the reason I think it’s a good choice in this case.

    When we see an empty list we expect that list to be used as a list and when we see a class instance, we expect that class to do something. But we don’t actually want this object to do anything: we only care about the uniqueness of this new object.

    We could have done this:

    1
    
    >>> INITIAL = ['completely unique value']
    

    But I find using object() less confusing than this because it’s clear: readers won’t have a chance to be confused by the listy-ness of a list.

    1
    
    >>> INITIAL = object()  # completely unique value
    

    Also if a confused developer Googles “what is object() in Python?” they might end up with some sort of explanation.

    Other cases for non-None placeholders

    There’s a word I’ve been avoiding using up to this point. I’ve only been avoiding it because I think I typically misuse it (or rather overuse it). The word is sentinel value.

    I suspect I overuse this word because I use it to mean any unique placeholder value, such as the INITIAL object we made before. But most definitions I’ve seen use “sentinel value” to specifically mean a value which indicates the end of a list, a loop, or an algorithm.

    Sentinel values are a thing that, when seen, indicate that something has finished. I think of this as a stop value: when you see a sentinel value it’s a signal that the loop or algorithm that you’re in should terminate.

    Before we weren’t using a stop value so much as an initial value.

    Here’s an example of a stop value; a true sentinel value:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    from itertools import zip_longest
    
    SENTINEL = object()
    
    def strict_zip(*iterables):
        """Variation of ``zip`` which requires equal-length iterables."""
        for values in zip_longest(*iterables, fillvalue=SENTINEL):
            if SENTINEL in values:
                raise ValueError("Given iterables must have the same length.")
            yield values
    

    We’re using the unique SENTINEL value above to signal that we need to stop looping and raise an exception. The presence of this value indicates that one of our iterables was a different length than the others and we need to handle this error case.

    Rely on identity checks for unique values

    Note that we’re implicitly relying on == above because we’re saying if SENTINEL in values which actually loops over values looking for a value that is equal to SENTINEL.

    If we wanted to be more strict (and possibly more efficient) we could rely on is, but we’d need to do some looping ourselves. Fortunately Python’s any function and a generator expression would make that a bit easier:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    from itertools import zip_longest
    
    SENTINEL = object()
    
    def strict_zip(*iterables):
        """Variation of ``zip`` which requires equal-length iterables."""
        for values in zip_longest(*iterables, fillvalue=SENTINEL):
            if any(v is SENTINEL for v in values):
                raise ValueError("Given iterables must have the same length.")
            yield values
    

    I’m fine with either of these functions. The first is a bit more readable even though this one is arguably a bit more correct.

    Identity checks are often faster than equality checks (== has to call the __eq__ method, but is does a straight memory ID check). But identity checks are also a bit more correct: if it’s uniqueness we care about, a unique memory location is the ultimate uniqueness check.

    When writing code that uses a unique object, it’s wise to rely on identity rather than equality if you can.

    This is what is was made for

    If we care about equality (the value of an object) we use ==, if we care about identity (the memory location) we use is.

    If you search my Python code for is you’ll pretty much only find the following things:

    1. x is None (this is the most common thing you’ll see)
    2. x is True or x is False (sometimes my tests get picky about True vs truthiness)
    3. iter(x) is x (iterators are a different Python rabbit hole)
    4. x is some_unique_object

    Those first two are checking for a singleton value (as recommended by PEP 8). The third one is checking if we’ve seen the same object twice (an iterator in this case). And the fourth one is checking for the presence of these unique values we’ve been discussing.

    The is operator checks whether two objects are exactly the same object in memory. You never want to use the is operator except for true identity checks: singletons (like None, True, and False), checking for the same object again, and checking for our own unique values (sentinels, as I usually call them).

    So when would we use object()?

    Oftentimes None is both the easy answer and the right answer for a unique placeholder value in Python, but sometimes you just need to invent your own unique placeholder value. In those cases object() is a great tool to have in your Python toolbox.

    When would we actually use object() for a uniqueness check in our own code?

    I can think of a few cases:

    1. Unique initial values: a starting value that should be distinguished from values seen later (default and initial in our min function)
    2. Unique stop values: a value whose presence tells us to stop looping/processing (a true sentinel value, as in strict_zip)
    3. Unique skip values: a value whose presence should be treated as an empty value to be skipped over (we didn’t see this, but it comes up with utilities like itertools.zip_longest sometimes)

    I hope this meandering through unique values has given you something (some non-None things) to think about.

    May your None values be unambiguous and your identity checks be truly unique.

    March 20, 2019 02:30 PM UTC


    Real Python

    13 Project Ideas for Intermediate Python Developers

    Learning the basics of Python is a wonderful experience. But the euphoria of just learning can be replaced by the hunger for hands-on projects. It’s normal to want to build projects, hence the need for project ideas.

    The problem though is that some projects are either too simple for an intermediate Python developer or too hard. This article will suggest projects you can work on as an intermediate Python developer. These project ideas will provide the appropriate level of challenge for you.

    In this article, you’ll learn:

    Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you'll need to take your Python skills to the next level.

    The Importance of Building Projects

    Working on projects is vital to pushing your career as a Python developer forward. They make you apply the skills and knowledge you’re acquiring.

    Projects can help you:

    There is a lot to gain from building projects as a Python developer.

    Choosing a Project Platform

    You need to build your software to run on a platform so that people who lack certain technical knowledge can use your software. The web, desktop, and command-line are the three major platforms you’ll want to build your projects for.

    Web

    Web applications are applications that run on the web, they can be accessed on any device without being downloaded, provided there is access to the internet. If you want your projects to be accessible by everyone with internet access, it needs to be a web application.

    A web application has a back end and front end. The back end is the part where the business logic is: your back-end code will manipulate and store data. The front end is the interface of the application: your front-end code will determine the look of a web application.

    As an intermediate Python developer, your major focus will be the back-end code. However, the front-end code is important too, so you will need some knowledge of HTML, CSS, and maybe JavaScript to create a simple-looking interface. Just the basics will be enough.

    Another option is to use Python for both the front end and back end. Thanks to the anvil library, which eliminates the need for HTML, CSS, and JavaScript, you can focus on Python code alone.

    You can build web applications with Python through web frameworks such as django and flask. The list of frameworks for building web applications using Python is long. There are plenty to choose from, but django and flask remain the most popular web frameworks.

    Desktop GUI

    Every time you perform a task on your PC, be it a desktop or laptop, it is through an application. As an intermediate Python developer, you can make your own desktop applications.

    You do not have to learn any front-end technology to create your own Graphical User Interface (GUI) applications, as you saw with web applications. You can build all the parts using Python.

    There are frameworks for building your desktop applications. PySimpleGUI is one of them, and it’s pretty user-friendly for an intermediate Python developer.

    An advanced GUI framework like PyQt5 is quite powerful, but it may have a steep learning curve.

    The software you create for the Desktop GUI is able to work on any of the Windows, Linux, or Mac operating systems. All you have to do after creating the project is compile it to an executable for your operating system of choice.

    Command-Line

    Command-line applications are those applications that work in a console window. This is the command prompt on Windows and the Terminal on Linux and Mac.

    You’d click to use a web or GUI application, but you’d type in commands for command-line applications. Users of command-line applications need to have some technical knowledge since they’ll need to use commands.

    Command-line applications may not be as beautiful or easy to use as web or GUI applications, but that doesn’t make them less powerful than web or GUI applications.

    You can improve the look of your command-line applications by applying colors to the text. There are libraries you can use for coloring, such as colorama and colored. You can spice things up and use some color.

    You can use frameworks such as docopt, argparse, and click to build your applications.

    Web Project Ideas

    In this section, you’ll see project ideas for the web. These project ideas can be classified as utility and education tools.

    Here are the project ideas:

    Content Aggregator

    Content is king. It exists everywhere on the web, from blogs to social media platforms. To keep up, you need to search for new information on the internet constantly. One way to stay updated is to check all the sites manually to see what the new posts are. But this is time consuming and quite tiring.

    This is where the content aggregator comes in: A content aggregator fetches information from various places online and gathers all of that information in one place. Therefore, you don’t have to visit multiple sites to get the latest info: one website is enough.

    With the content aggregator, all of the latest information can be gotten from one site that aggregates all the content. People can see the posts that interest them and can decide to find out more about them without traipsing all over the internet.

    Examples of Content Aggregators

    Here are some implementations of the Content Aggregator idea:

    Technical Details

    The main objective of this project idea is to aggregate content. First, you need to know what sites you’ll want the Content Aggregator to get content from. Then, you can use libraries such as requests for sending HTTP requests and BeautifulSoup to parse and scrape the necessary content from the sites.

    Your application can implement its content aggregation as a background process. Libraries such as celery or apscheduler can help with that. You can try out apscheduler. It’s great for small background processes.

    After scraping content from various sites, you’ll need to save it somewhere. So, you’ll use a database to save the scraped content.

    Extra Challenge

    For a tougher challenge, you can add more websites. This will help you learn how to study and extract information from websites.

    You can also have users subscribe to certain sites that you aggregate. Then, at the end of the day, the content aggregator will send the articles for that day to the email address of the user.

    Regex Query Tool

    You and I deal with text daily. This article, which is also text, has a structure. This makes it easier for you to understand. Sometimes, you need to find certain information in text, and using the regular search tool in text editors can be ineffective.

    This is where the Regex Query Tool comes in. A regex is a set of strings, so the regex query tool will check for the validity of the queries. When the regex matches patterns in the text, it tells the user and highlights the matched patterns. So, your Regex Query Tool will check the validity of the regex strings passed in by the user.

    With the Regex Query Tool, users can quickly check the validity of their regex strings on the web. This makes it easier for them, instead of having to check the strings with a text editor.

    Examples of Regex Query Tools

    Here are some implementations of the Regex Query Tool idea:

    Technical Details

    The main objective of this type of project is to tell the user the validity of the inputted query strings. You can make it give a positive or negative response such as Query String Is Valid and Query String Is Invalid, implementing the positive response in green and the negative in red.

    You don’t have to implement the query tool from scratch. You can use Python’s standard re library, which you can use to run the query strings on the inputted text. The re library will return None when the query string matches nothing, and it’ll return the matched strings when positive.

    Some users may not understand regex fully, so you can make a page to explain how regex works. You can make documentation that is interesting enough to keep the users excited about learning and understanding regex.

    Extra Challenge

    Making a project that just returns the validity of the regex is fine. But you can also add a replacement feature. This means the application will check for the validity of the regex and also allow users to replace the matched strings with something else. So the tool is no longer a find tool but also a replace tool.

    URL Shortener

    URLs can be extremely long and not user-friendly. When people share links or even try to remember a URL, it’s difficult because most URLs are filled with more difficult characters and don’t form meaningful words.

    This is where the URL Shortener comes in. A URL Shortener reduces the characters or letters in a URL, making them easier to read and remember. A URL like xyz.com/wwryb78&svnhkn%sghq?sfiyh can be shortened to xyz.com/piojwr.

    With the URL Shortener, URLs become a joy to work with.

    Examples of URL Shorteners

    Here are some implementations of the URL Shortener idea:

    Technical Details

    The main objective of this project idea is to shorten URLs. The main task the application will accomplish is to shorten URLs and then redirect users to the original URL when the shortened URL is visited.

    In the application, the users will input the original URL, and they will get the new, shortened URL as the result. To do this, you can use a combination of the random and string modules to generate the characters for the shortened URL.

    Since users will visit the shortened URL days, months, or even years after, you’ll need to save the original and shortened URLs in a database. When a request comes in, the application checks if the URL exists and redirects to the original, or else it redirects to a 404 page.

    Extra Challenge

    Generating a shortened URL with random characters makes for a better URL than the long, random ones. But, you can make the result better for the users. You can add a feature to customize URLs, so the users can customize the generated URLs themselves.

    Without a doubt, a custom xyz.com/mysite URL is better than a randomly generated xyz.com/piojwr URL.

    Post-It Note

    It’s human to have many thoughts and ideas in a day, but it’s also human to forget. One way to work around forgetting things is to jot them down before they disappear into thin air. While some of forgotten thoughts and ideas may be trivial, some can be quite powerful.

    This is where a Post-It note comes in: A Post-It note is a small paper with low-tack adhesive at the back, making it attachable to surfaces such as documents, walls. Post-It notes make it easier to jot things down. The Post-It note project idea is something similar. It allows users to jot things down, making them accessible anywhere, since it’s a web application.

    With the Post-It note, people can now jot things down anywhere, without the fear of forgetting things or misplacing the notes—which is a possibility with physical notes.

    Examples of Post-It Notes

    Here are some implementations of the Post-It Note idea:

    Technical Details

    The main objective of this project is to allow users to jot down thoughts. This means that each user will have their own notes, so the application will need to have an account creation feature. This ensures that the notes of each user remain private to them.

    django comes with a user authentication system, so it may be a good choice. You can use other frameworks like bottle or flask, but you’ll have to implement the user authentication system on your own.

    Since users may need to separate their notes under different sections, implementing a feature to allow users to categorize their notes will make the application more useful.

    As an example, you may need to have notes on algorithms and data structures, so you’ll need to be able to separate the notes in those categories.

    You’ll need to store the information and notes of each user, so a database becomes an essential part of this project. The MySQLdb module can be used if you want to use a MySQL database or the psycopg2 module for a PostgreSQL database. There are other modules you can use, but it all depends on the database you choose to use.

    Extra Challenge

    Since it’s human for users to forget their ideas, it’s also human for them to forget that they even made a note somewhere. You can add a feature to remind users of their notes. This feature will allow users to set a time for the reminder, so the application will send the reminder to the users when it’s time, by email.

    Quiz Application

    Knowledge is power. There are so many things in the world to learn, and quizzes help in testing the understanding of those concepts. You, as an intermediate Python developer, do not have to understand everything about the language. Taking tests is one way to find out things you don’t fully understand.

    This is where the Quiz Application comes in. The Quiz Application will present questions to the users and expect the right answers to those questions. Think of the Quiz Application as a kind of questionnaire.

    With the Quiz Application, special users you can call administrators will be allowed to create tests, so regular users can answer the questions and test their understanding of the topics in the quiz.

    Examples of Quiz Applications

    Here are some implementations of the Quiz Application idea:

    Technical Details

    The main objective of this project is to set quizzes and have people answer them. Therefore, users should be able to set questions, and other users should be able to answer those questions. The application will then display the final score and the right answers.

    If you want users to be able to have a record of their scores, you may have to implement an account creation feature.

    Users creating the tests should be able to create tests with the questions and answers by simply uploading a text file. The text file will have a format that you can decide, so the application can convert from a file to a quiz.

    You’ll need to implement a database for this project. The database will store the questions, possible answers, correct answers, and the scores for each user.

    Extra Challenge

    For more of a challenge, you can allow users to add timers to the quizzes. This way, the creators of a quiz can determine how many seconds or minutes a user should spend on each question in the quiz.

    It would be great to also have a quiz-sharing feature, so users can share interesting quizzes with their friends on other platforms.

    GUI Project Ideas

    In this section, you’ll see project ideas for Graphical User Interfaces. These project ideas can be classified as entertainment, finance, and utility tools.

    Here’s are the project ideas:

    MP3 Player

    Audio is as important as text today if not more important. Since audio files are digital files, you’ll need a tool that can play them. Without a player, you’ll never be able to listen to the contents of an audio file.

    This is where the MP3 Player comes in. The MP3 Player is a device for playing MP3s and other digital audio files. This MP3 Player GUI project idea attempts to emulate the physical MP3 Player. You can build software that allows you play an MP3 files on your desktop or laptop computer.

    When you are done building the MP3 Player project, users can play their MP3 files and other digital audio files without having to purchase a physical MP3 Player. They’ll be able to play the MP3 files using their computers.

    Examples of MP3 Players

    Here are some implementations of the MP3 Player idea:

    Technical Details

    The main objective of this project is to allow users to play MP3 and digital audio files. To be engaging for users, the application has to have a simple but beautiful user interface.

    You can have an interface for listing the available MP3 files. You can also give users the option to list other digital audio files that are not MP3.

    The users will also expect the MP3 Player to have an interface that shows information on the file that is playing. Some of the information you can include are the name of the file, its length, the amount played, and the amount not played, in minutes and seconds.

    Python has libraries that can play audio files, such as pygame, which allows you to work with multimedia files in few lines of code. You can also check out pymedia and simpleaudio.

    These libraries can handle a lot of digital audio files. They can handle other file types, not just the MP3 files.

    You can also implement a feature that allows users to create a playlist. To do this, you’ll need a database to store information on the created playlists. Python’s sqlite3 module allows you to use the SQLite database.

    The SQLite database is a better option in this case, because it is file based and easier to set up than other SQL databases. While SQLite is file based, it is better for saving data than a regular file.

    Extra Challenge

    For a more exciting challenge, you can add a feature to allow the MP3 player to repeat currently playing files or even shuffle the list of files to be played.

    It’s also possible to implement a feature that allows users to increase and decrease the playing speed of the audio file. Users will find this interesting, as they’ll be able to play files at a slower or faster pace than usual.

    Alarm Tool

    As they say, “Time and tide wait for no man.” But with a lot of things going on in our lives, it’s difficult to not lose track of time. To be able to keep track of time, a reminder is needed.

    This is where the Alarm Tool comes in. An alarm is a device that gives an audio or visual signal about a certain condition. This Alarm Tool project idea is an attempt to build an alarm as software. The Alarm Tool gives an audio signal when a certain condition is met. The set time is the certain condition in this case.

    With the Alarm Tool, users can set alarms to remind them of things at certain times of the day. The Alarm Tool project will work from the user’s laptop or desktop device, so they do not have to purchase a physical timer.

    Examples of Alarm Tools

    Here are some implementations of the Alarm Tool idea:

    Technical Details

    The main objective of this project is to activate audio signals at certain times of the day. So, timing and the audio signal to be played are the most important parts of the Alarm Tool.

    The Alarm Tool should allow users to create, edit, and delete alarms. It should also have an interface that lists all the alarms, provided they have not being deleted by the user. So, it should list the active and inactive alarms.

    Since it is an alarm, the application has to play tones at the set time. There are libraries for playing audio, like the pygame library.

    In your code logic, the application has to keep checking for set alarm times. When the time is reached, it triggers a function to play the alarm tone.

    Since the application will check for set alarm times, it means the application has to save the alarms in a database. The database should store things like the alarm date, time, and tone location.

    Extra Challenge

    As an extra feature, you can allow users to set recurring alarms. They’ll be able to set alarms that will ring at a certain time on certain days of the week, every week. As an example, an alarm can be set at 2:00 PM every Monday.

    You can also add a snooze feature, so your users can snooze alarms instead of only dismissing them.

    File Manager

    The number of files on the personal computer of an average PC user is pretty high. If all of those files were placed in a single directory, it would be difficult to navigate and find files or directories. So, there is a need to arrange the files and manage them properly.

    This is where a file manager comes in. A file manager allows users to manage files and directories through a user interface. While files can be managed through the command-line, not all users know how to do that.

    With a file manager, users can arrange, access, and administer their files and directories properly without knowing how to use the command line. Some of the tasks a file manager allows users to perform includes copying, moving, and renaming files or directories.

    Examples of File Manager Tools

    Here are some implementations of the File Manager idea:

    Technical Details

    The main objective of the file manager project is to give users an interface to manage their files. Users want a file manager that has a file management tool that looks good and is easy to use.

    You can use the PySimpleGUI library to create unique user interfaces with a powerful widget, without having to deal with a lot of complexity.

    Your users should be able to perform simple tasks like creating new directories or empty text files. They should also be able to copy and move files or directories.

    The sys, os, and shutil libraries will be quite useful for this project, as they can be used to execute actions on the files in the background, while the user clicks away.

    The grid and list views are popular views today, so you can implement both in the application. This gives the user the option to choose which view option is suitable for them.

    Extra Challenge

    To make the file manager a bit more advanced, you can implement a search feature. So users can search for files and directories without having to find them manually.

    You can also implement a sort feature. This will allow users to sort files according to different orders, such as time, alphabetical order, or size.

    Expense Tracker

    We have daily expenses, from groceries to clothing to bills. There are so many expenses that it’s normal to lose track of them and keep spending till we’re almost out of cash. A tracker can help people watch their expenses.

    This is where the expense tracker comes in. An expense tracker is a software tool that allows users to keep track of their expenses. It can also analyze the expenses, depending on how advanced it is, but let’s keep it simple for now.

    With the expense tracker, users can set a budget and track their spending so as to make better financial decisions.

    Examples of Expense Trackers

    Here are some implementations of the Expense Tracker idea:

    Technical Details

    The main objective of this project is to keep track of the user’s expenses. Some statistical analysis has to be done to be able to give users correct information on their expenses and help them spend better.

    While tracking the expenses is the key thing, a good interface is also important. With PySimpleGUI, you can create a unique interface to improve the experience of the users.

    PyData libraries such as pandas and matplotlib can be helpful for building the expense tracker.

    The pandas library can be used for the data analysis, and the matplotlib library can be used for plotting graphs. Graphs will give the users a visual representation of their expenses, and a visual representation is usually easier to understand.

    The application will receive data from the users. The data here is the inputted expenses. So, you’ll have to store the expenses in a database. The SQLite database is a good database choice for this project since it can be set up quickly. You can use sqlite3 module for the SQLite database.

    Extra Challenge

    For your users to benefit from this project, they’ll have to input their expenses regularly, which might slip their mind. It could be useful for you to implement a reminder feature. So the application will send a notification at certain times of the day or the week, reminding them to make use of the expense tracker.

    Command-Line Project Ideas

    In this section, you’ll see project ideas for the command-line. The project ideas discussed can be classified as utility tools.

    Here’s are the project ideas:

    Contact Book

    We come across lots of people daily. We make acquaintances and friends. We get their contacts to keep in touch later on. Sadly, keeping the received contact details can be hard. One way to do this is to write the contact details down. But this is not secure as the physical book can easily be lost.

    This is where the Contact Book project comes in. A contact book is a tool for saving a contact’s details, such as name, address, phone number, and email address. With this contact book project, you can build a software tool that people can use to save and find contact details.

    With the contact book project idea, users can save their contacts with less risk of losing the saved contact details. It’ll always be accessible from their computer, through the command-line.

    Examples of Contact Book Tools

    There are Contact Book applications, but it’s rare to find command-line Contact Book products, as most are web, mobile, or GUI applications.

    Here are some implementations of the Contact Book idea:

    Technical Details

    The main objective of this project is to save contact details. It’s important that you set up the commands users can use to enter the contact details. You can use the argparse or click command-line frameworks. They abstract a lot of complex stuff, so you only have to focus on the logic to be run when executing commands.

    Some features you should implement include the commands to delete contacts, update contact information, and list saved contacts. You can also allow users to list contacts using different parameters, such as alphabetical order or contact creation date.

    Since it’s a command-line project, the SQLite database will be fine for saving contacts. SQLite is user-friendly to set up. You may save the contact details in a file, but a file will not offer the benefits you can gain from using SQLite, such as performance and security.

    To use the SQLite database in this project, the Python sqlite3 module will be very useful.

    Extra Challenge

    Remember how the database is stored on the user’s computer? What if something happens, like the user losing their files? It means they’ll also lose the contact details.

    You can challenge yourself further and backup the database to an online storage platform. To do this, you can upload the database files to the cloud at certain intervals.

    You can also add a command that allows users to backup the database themselves. This way, the user can still have access to the contacts if the database file is lost.

    You should note that you may need some form of identification, so the contact book can tell which database file belongs to which user. Implementing a user authentication feature is one way to go about it.

    Site Connectivity Checker

    When you visit a URL, you expect to get the requested pages on your browser. But this is not always the case. Sometimes, sites can be down, so you won’t get the desired results. Instead, you’ll be presented with error messages. You can keep trying a site that is down, till it comes up and you get the information you need.

    This is where the Site Connectivity Checker project comes in. The Site Connectivity Checker visits a URL and returns the status of the URL: it is either live or not. The Site Connectivity Checker will visit the URL at intervals, returning the results of each visit.

    Instead of manually visiting a URL, a Site Connectivity Checker can do all of that manual work for you. This way, you’ll only get the results of the check without having to spend time on the browser, waiting for the site to go live.

    Examples of Site Connectivity Checkers

    Here are some implementations of the Site Connectivity Checker idea:

    Technical Details

    The main objective of this project is to check the status of sites. So, you need to write code for checking the status of a website.

    You can choose to use either TCP or ICMP for your connections. The socket module is one to check out. You can also read Socket Programming in Python (Guide).

    Through your chosen framework, be it the docopt, click, or argparse framework, you can add commands to allow users to add and remove sites from the list of sites to be checked.

    The users should also be able to start the tool, stop it, and determine the intervals.

    Since you’ll have to save the list of files to be checked, you can either save it in a file (just a list of sites) or use a SQLite database through the sqlite3 module.

    Extra Challenge

    The application can check for the connectivity status of sites and display the results to the command-line. But this will require the user to keep checking the command-line.

    You can increase the challenge and implement a notification feature. The notification feature can be a sound played in the background to alert the user when a site’s status changes. You’ll need a database to store the previous status of a site. That’s the only way the tool can tell when the status changes.

    Bulk File Rename Tool

    Sometimes, you need to name all the files in a directory according to certain conventions. For example, you can name all the files in a directory with File0001.jpg, where the numbers increase based on the number of files in the directory. Doing this manually can be stressful and repetitive.

    The Bulk File Rename Tool allows users to rename a large number of files, without having to manually rename files.

    This saves users a lot of time. It spares them the trouble of having to do boring repetitive work and make mistakes. With the Bulk File Rename Tool, users can rename files in a couple of seconds without any mistakes.

    Examples of Bulk File Rename Tools

    Here are some implementations of the Bulk File Rename idea:

    Technical Details

    The main objective of this project idea is to rename files. So, the application needs to find a way to manipulate the target files. The os, sys, and shutil libraries will be useful for a large part of this project.

    Your users will be able to rename all the files in the directory, using naming conventions. Therefore, they should be able to pass in the naming convention of choice. The regex module will help match the required naming patterns, if you understand how regex works.

    A user may want to pass in a naming convention such as myfiles as part of the commands and expect that the tool renames all the files like myfilesXYZ, where XYZ is a number. They should also be able to choose the directory where the files to be renamed are.

    Extra Challenge

    The major challenge in this project is to rename all the files in a directory. But users may only need to name a certain number of files. To test your skills, you can implement a feature to allow users to choose the number of files to be renamed, instead of all the files.

    Note that renaming only a certain number of files will require the tool to sort the files based on alphabetical order, time of file creation, or file size, depending on the user’s requirements.

    Directory Tree Generator

    Directories are like family trees: each directory has a particular relationship with other directories. No directories ever stays on its own, except an empty root directory.

    When you’re working with files and directories, it is difficult to see the relationship between directories, as you can only see what exists in the current directory. You’re either using a file manager or working from the command-line.

    With a Directory Tree Generator, you can see the relationship between files and directories like a tree or a map.

    This makes it easier to understand the positioning of files and directories. A directory tree map is important when you’re explaining certain concepts, and a Directory Tree Generator makes it easier to get a visual representation of the file and directory relationships.

    Examples of Directory Tree Generators

    Here are some implementations of the Directory Tree Generator idea:

    Technical Details

    The main objective of the Directory Tree Generator is to visualize the relationships between files and directories. The os library can be very useful in listing the files and directories in a chosen directory.

    Using a framework such as docopt or argparse helps abstract a lot of stuff, allowing you to focus on writing code for the application’s logic.

    In the application’s logic, you can decide how you want to represent files or directories. Using different colors is a brilliant way to go about it. You can use the colored library to print the files and directories in different colors.

    You can also decide how deep you’d like the Directory Tree Generator to go. For example, if a directory has children directories twelve levels deep, you may decide to go only as deep as the fifth level.

    If you wish, you can also let the user decide how deep they want the Directory Tree Generator to go.

    Extra Challenge

    Since the results of the generated directory tree will be on the command-line, you can go one step further. You can have the generator create images of the directory tree, so it’ll basically turn the text into an image.

    You’ll find the pillow library useful for doing this.

    Tips for Working on Projects

    Working on projects can be difficult. That’s one reason why motivation and interest in a project will make it a less daunting task.

    If you’re interested in a project, you’ll be able to put in the time to research as well as find libraries and tools that will help you with the project.

    Here are some tips:

    Conclusion

    In this article, you’ve seen a couple of Python project ideas you may find interesting.

    The project ideas cover a range of platforms. You saw project ideas for the Web, GUI, and Command-line platforms.

    You can choose to build a project for different platforms. Using the URL Shortener as an example, you may choose to build one for the Web, GUI, or the Command-line.

    Since you’re an intermediate Python developer, these projects can be quite challenging but interesting.

    The best way to make a project happen is to just get started. In no time, you’ll be finished and discover how much you’ve benefited from working on a project!


    [ 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 ]

    March 20, 2019 02:00 PM UTC


    pythonwise

    Speed: Default value vs checking for None

    Python's dict has a get method. It'll either return an existing value for a given key or return a default value if the key is not in the dict. It's very tempting to write code like val = d.get(key, Object()), however you need to think about the performance implications. Since function arguments are evaluated before calling the function, this means the a new Object will be created regardless if it's in the dict or not. Let's see this affects performance.

    get_default will create new Point every time and get_none will create only if there's no such object, it works since or evaluate it's arguments lazily and will stop once the first one is True.

    First we'll try with a missing key:

    In [1]: %run default_vs_none.py                                     
    In [2]: locations = {}  # name -> Location 
    In [3]: %timeit get_default(locations, 'carmen')
    384 ns ± 2.56 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
    In [4]: %timeit get_none(locations, 'carmen')
    394 ns ± 1.61 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)


    Not so much difference. However if the key exists:

    In [5]: locations['carmen'] = Location(7, 3)
    In [6]: %timeit get_default(locations, 'carmen')                 
    377 ns ± 1.84 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
    In [7]: %timeit get_none(locations, 'carmen')
    135 ns ± 0.108 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

    We get much faster results.

    March 20, 2019 11:50 AM UTC


    leftmouseclickin

    Plotting the average directional movement index values

    Our Own Score

    Hello and welcome back, in this chapter we will continue developing our Forex and Stock application. We will create a method to plot the average directional movement index values. The average directional index (ADX) is a technical analysis indicator used by some traders to determine the strength of a trend. The trend can be either up or down, and this is shown by two accompanying indicators, the Negative Directional Indicator (-DI) and the Positive Directional Indicator (+DI).

    Below is the modified version of the project with a plot adx button which will call the plot adx method after it has been clicked.

    import json
    from tkinter import *
    import tkinter.ttk as tk
    from alpha_vantage.foreignexchange import ForeignExchange
    from alpha_vantage.techindicators import TechIndicators
    from alpha_vantage.timeseries import TimeSeries
    import matplotlib.pyplot as plt
    from alpha_vantage.sectorperformance import SectorPerformances
    
    win = Tk() # Create tk instance
    win.title("Real Forex n Stock") # Add a title
    win.resizable(0, 0) # Disable resizing the GUI
    win.configure(background='white') # change window background color
    
    selectorFrame = Frame(win, background="white") # create the top frame to hold base and quote currency combobox
    selectorFrame.pack(anchor = "nw", pady = 2, padx=10)
    currency_label = Label(selectorFrame, text = "Select base currency / quote currency :", background="white")
    currency_label.pack(anchor="w") # the currency pair label
    
    selector1Frame = Frame(win, background="white") # create the middle frame to hold base and quote currency combobox
    selector1Frame.pack(anchor = "nw", pady = 2, padx=10)
    stock_label = Label(selector1Frame, text = "Select Stock / Time Interval / Series type / Moving average type / Fast Period / Slow Period :", background="white")
    stock_label.pack(anchor="w") # the stock label
    
    curr1 = tuple() # the tuple which will be populated by base and quote currency
    currency_list = ['AUD', 'BCH', 'BNB', 'BND', 'BTC', 'CAD', 'CHF', 'CNY', 'EOS', 'EUR', 'ETH', 'GBP', 'HKD', 'JPY', 'LTC', 'NZD', 'MYR', 'TRX', 'USD', 'USDT', 'XLM', 'XRP'] # major world currency pairs
    
    # populate the combo box for both the base and quote currency
    for key in currency_list:
        curr1 += (key, )
    
    # populate the stock symbol tuple
    f = open("stock.txt", "r")
    curr2 = tuple()
    for line in f.readlines():
        curr2 += (line.replace('\n', ''),)
    f.close()
    
    # Create a combo box for base currency
    base_currency = StringVar() # create a string variable
    based = tk.Combobox(selectorFrame, textvariable=base_currency)
    based['values'] = curr1
    based.pack(side = LEFT, padx=3)
    
    # Create a combo box for quote currency
    quote_currency = StringVar() # create a string variable
    quote = tk.Combobox(selectorFrame, textvariable=quote_currency)
    quote['values'] = curr1
    quote.pack(side = LEFT, padx=3)
    
    # Create a combo box for stock items
    stock_symbol = StringVar() # create a string variable
    stock = tk.Combobox(selector1Frame, textvariable=stock_symbol)
    stock['values'] = curr2
    stock.current(0)
    stock.pack(side = LEFT, padx=3)
    
    interval = tk.Combobox(selector1Frame)
    interval['values'] = ('1min', '5min', '15min', '30min', '60min', 'daily', 'weekly', 'monthly')
    interval.current(0)
    interval.pack(side = LEFT, padx=3)
    
    price_type = tk.Combobox(selector1Frame)
    price_type['values'] = ('close', 'open', 'high', 'low')
    price_type.current(0)
    price_type.pack(side =LEFT, padx=3)
    
    matype_type = tk.Combobox(selector1Frame, width=37)
    matype_type['values'] = ('Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)')
    matype_type.current(0)
    matype_type.pack(side =LEFT, padx=3)
    mattype_list = ['Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)']
    
    # fill up the fast period and slow period combo boxes with integer ranging from 2 to 10,000
    fa = tuple()
    for i in range(2, 10001):
        fa += (i, )
    
    fast_pe = tk.Combobox(selector1Frame)
    fast_pe['values'] = fa
    fast_pe.current(0)
    fast_pe.pack(side=LEFT, padx=3)
    
    slow_pe = tk.Combobox(selector1Frame)
    slow_pe['values'] = fa
    slow_pe.current(0)
    slow_pe.pack(side=LEFT, padx=3)
    
    # create text widget area
    s = StringVar() # create string variable which will be used to fill up the Forex data
    # create currency frame and text widget to display the incoming forex data
    currencyFrame = Frame(win)
    currencyFrame.pack(side=TOP, fill=X)
    currency = Label(currencyFrame)
    currency.pack(fill=X)
    text_widget = Text(currency, fg='white', background='black')
    text_widget.pack(fill=X)
    s.set("Click the find button to find out the currency exchange rate")
    text_widget.insert(END, s.get())
    
    buttonFrame = Frame(win) # create a bottom frame to hold the find button
    buttonFrame.pack(side = BOTTOM, fill=X, pady = 6, padx=10)
    
    # first get the api key and secret from the file
    f = open("alpha.txt", "r")
    api_key = f.readline()
    f.close()
    api_key = api_key.replace('\n', '')
    
    def get_exchange_rate(): # this method will display the incoming forex data after the api called
    
        try:
            cc = ForeignExchange(key= api_key)
            from_ = based.get()
            to_ = quote.get()
    
            countVar = StringVar()  # use to hold the character count
            text_widget.tag_remove("search", "1.0", "end")  # cleared the hightlighted currency pair
    
            if(from_ != '' and to_ != '' and from_ != to_):
                data, _ = cc.get_currency_exchange_rate(from_currency=from_, to_currency=to_)
                exchange_rate = dict(json.loads(json.dumps(data)))
                count = 1
                sell_buy = str(count) + ".) Pair : " + exchange_rate['1. From_Currency Code'] + "(" + exchange_rate['2. From_Currency Name'] + ")" + " / " + exchange_rate['3. To_Currency Code']+"(" + exchange_rate['4. To_Currency Name'] + ") : "  + str(exchange_rate['5. Exchange Rate']) + '\n'
                text_widget.delete('1.0', END)  # clear all those previous text first
                s.set(sell_buy)
                text_widget.insert(INSERT, s.get())  # display forex rate in text widget
                pos = text_widget.search(from_, "1.0", stopindex="end", count=countVar)
                text_widget.tag_configure("search", background="green")
                end_pos = float(pos) + float(0.7)
                text_widget.tag_add("search", pos, str(end_pos))  # highlight the background of the searched currency pair
                pos = float(pos) + 2.0
                text_widget.see(str(pos))
    
        except:
            print("An exception occurred")
    
    def plot_stock_echange():
    
        try:
            stock_symbol_text = stock.get() # get the selected symbol
            if(stock_symbol_text!= ''):
                ts = TimeSeries(key=api_key, output_format='pandas')
                data, meta_data = ts.get_intraday(symbol=stock_symbol_text, interval='1min', outputsize='full')
                data['4. close'].plot()
                stock_title = 'Intraday Times Series for the ' + stock_symbol_text + ' stock (1 min)'
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_stock_technical():
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_bbands(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'BBbands indicator for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_op(): # plot the Absolute price oscillator (APO)
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_apo(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), fastperiod = fast_pe.get(), slowperiod= slow_pe.get())
                data.plot()
                stock_title = 'Absolute Price Oscillator (APO) for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An exception occurred")
    
    def plot_adxr(): # plot the average directional movement index rating
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_adxr(symbol=stock_symbol_text, interval=interval.get(), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'Average directional movement index rating for ' + stock_symbol_text + ' at ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An exception occurred")
    
    def plot_adx(): # plot the average directional movement index
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_adx(symbol=stock_symbol_text, interval=interval.get(), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'Average directional movement index for ' + stock_symbol_text + ' at ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An error exception occurred")
    
    def plot_sector_performance():
    
        sp = SectorPerformances(key=api_key, output_format='pandas')
        data, meta_data = sp.get_sector()
        data['Rank A: Real-Time Performance'].plot(kind='bar')
        plt.title('Real Time Performance (%) per Sector')
        plt.tight_layout()
        plt.grid()
        plt.show()
    
    def plot_ad():
    
        try:
            stock_symbol_text = stock.get()  # get the selected stock symbol
            if (stock_symbol_text != ''):
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_ad(symbol=stock_symbol_text, interval=interval.get())
                data.plot()
                stock_title = 'Chaikin A/D line values for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    action_vid = tk.Button(buttonFrame, text="Calculate Exchange Rate", command=get_exchange_rate) # button used to find out the exchange rate of currency pair
    action_vid.pack(side=LEFT, padx=2)
    
    action_stock_plot = tk.Button(buttonFrame, text="Plot Stock", command=plot_stock_echange) # button used to plot the intra-minute stock value
    action_stock_plot.pack(side=LEFT, padx=2)
    action_technical_plot = tk.Button(buttonFrame, text="Plot Technical", command=plot_stock_technical) # button used to plot the 60 minutes stock technical value
    action_technical_plot.pack(side=LEFT, padx=2)
    action_sector_plot = tk.Button(buttonFrame, text="Plot Sector Performance", command=plot_sector_performance) # button used to plot the sector performance graph
    action_sector_plot.pack(side=LEFT, padx=2)
    action_ad_plot = tk.Button(buttonFrame, text="Plot AD Line", command=plot_ad) # button used to plot the A/D line graph
    action_ad_plot.pack(side=LEFT, padx=2)
    action_ad_op = tk.Button(buttonFrame, text="Plot APO Line", command=plot_op) # button used to plot the APO line graph
    action_ad_op.pack(side=LEFT, padx=3)
    action_adxr = tk.Button(buttonFrame, text="Plot ADXR Line", command=plot_adxr) # button used to plot the average directional movement index rating
    action_adxr.pack(side=LEFT, padx=3)
    action_adx = tk.Button(buttonFrame, text="Plot ADX Line", command=plot_adx) # button used to plot the average directional movement index
    action_adx.pack(side=LEFT, padx=3)
    win.iconbitmap(r'ico.ico')
    win.mainloop()
    

    After running the above program below is what we will get.

    Like, share or follow me on Twitter.

    March 20, 2019 11:17 AM UTC


    Shyama Sankar Vellore

    Python Sets: Cheat Sheet

    A cheat sheet for sets in Python. What is the 'set' datatype in Python? How is it used?

    Jump to the cheat sheet

    Key points

    • Unlike lists and tuples, a set is an unordered collection of unique elements.
    • A set can be created using the set() constructor. It takes an optional iterable as input.
    • Sets with some elements can also be initialized using the curly braces (e.g., {1, 2, 3}).
    • However, curly braces cannot be used to create an empty set. Using empty curly braces, i.e., {}, creates a dictionary datatype in Python.
    • 'in' operator can be used to check the presence of an element in a set.
    • Sets support the mathematical set operations like union, intersection, difference, symmetric difference, etc.
    • Sets are mutable, we can add or remove elements from them.

    Cheat sheet

    Useful resources and references

    March 20, 2019 07:19 AM UTC

    March 19, 2019


    Codementor

    Clean up and remove a Python3 homebrew install

    tl;dr how to clean up your Python3 homebrew install

    March 19, 2019 08:47 PM UTC


    PyCoder’s Weekly

    Issue #360 (March 19, 2019)

    #360 – MARCH 19, 2019
    View in Browser »

    The PyCoder’s Weekly Logo


    How to Build a Python GUI Application With wxPython

    In this step-by-step tutorial, you’ll learn how to create a cross-platform graphical user interface (GUI) using Python and the wxPython toolkit. A graphical user interface is an application that has buttons, windows, and lots of other widgets that the user can use to interact with your application.
    REAL PYTHON

    Simplify Your Python Developer Environment

    How three tools (pyenv, pipx, pipenv) make for smooth, isolated, reproducible Python developer and production environments.
    MASON EGGER • Shared by Mason Egger

    Automated Code Reviews for Python

    alt

    Take the hassle out of code reviews—Codacy flags errors so you can fix them quickly. Address security concerns, code duplication, code complexity and drops in coverage, directly from your workflow. Click here to get started →
    CODACY sponsor

    When C Extensions Crash: Easier Debugging for Your Tests

    Learn how to prepare for crashes in advance, so when they do occur you can quickly figure out which part of the codebase caused them: The standard library’s faulthandler, verbose test runs, package listing, and catchsegv on Linux.
    ITAMAR TURNER-TRAURING

    Why Operators Are Useful

    Latest blog post from Guido, related to the recent discussion about Python getting + and - operators for merging dictionaries (PEP 584).
    GUIDO VAN ROSSUM • Shared by Ricky White

    Python Decorators 101

    See step-by-step what Python decorators are and how you can use them to make your own code more Pythonic and expressive.
    REAL PYTHON video

    Tuple Ordering and Deep Comparisons in Python

    Nice deep dive on comparison operators in Python.
    TREY HUNNER • Shared by Ricky White

    urllib CRLF Injection Vulnerability

    The current Python 2.x and 3.x implementation of urllib does not encode the \r\n sequence in the query string, which allows an attacker to manipulate a HTTP header with the \r\n sequence in it, so the attacker can insert arbitrary content to the new line of the HTTP header.
    PYTHON.ORG

    Give Me Back My Monolith

    “It feels like we’re starting to pass the peak of the hype cycle of microservices.” Interesting counterpoint to the “everything should be broken down into microservices” hypetrain. Not Python-specific, but worth a read nonetheless.
    CRAIG KERSTIENS opinion

    Discussions

    Guido Explains Why Python Uses 0-Based Indexing

    Google Plus is shutting down soon, so here’s a final hurrah.
    GOOGLE.COM

    There Are Some Huge Speedups in Python 3.8. Will They Also Be Put Into the Older Versions?

    REDDIT

    Python Jobs

    alt

    Brought to you by Indeed Prime

    sponsor

    Apply today to see what job opportunities are waiting for you!

    Machine Learning and Data Science Developer (Austin, TX)

    Protection Engineering Consultants LLC

    Lead Python Developer (Toronto, Canada)

    Kognitiv

    Senior Systems Engineer (Hamilton, Canada)

    Preteckt

    Python Software Engineer (Berlin, Germany)

    Wooga

    Computer Science Teacher (Pasadena, CA)

    ArtCenter College of Design

    Senior Python Engineer (New York, NY)

    15Five

    More Python Jobs >>>

    Articles & Tutorials

    Understanding the Python Mock Object Library

    In this tutorial, you’ll learn how to use the Python mock object library, unittest.mock, to create and use mock objects to improve your tests. Obstacles like complex logic and unpredictable dependencies make writing valuable tests difficult, but unittest.mock can help you overcome these obstacles.
    REAL PYTHON

    How I Translated a Mathematical Algorithm Into Code: TF-IDF to Python

    Does your brain short-circuit when you see a mathematical algorithm? Don’t worry, you’re not alone. In this post you’ll see how the author worked her way through an algorithm, namely TF-IDF, and got it up and running in Python. Nice writeup!
    SILKE HENDERICKX • Shared by Silke Henderickx

    Take ActiveState’s ~7 Min Survey for a Chance to Win a Lego Star Wars TIE Fighter

    alt

    We want to know your pain points building & programming open source languages. We’ve got 3 cool prizes too. Click to speed through this ~7min survey →
    ACTIVESTATE sponsor

    10 Python Image Manipulation Tools

    Nice overview of Python libraries that provide an easy and intuitive way to transform images and make sense of the underlying data.
    PARUL PANDEY

    Tips and Tricks to Write LaTeX Papers in With Figures Generated in Python

    Some nice tips and example code for writing scientific papers in LaTeX, with figures generated in Python.
    VINCENT ETTER

    Make Python Delete Your Unwanted Emails Periodically

    How to use the Gmail API to create a Python script which will automatically search & delete the messages matching your query.
    UDIT VASHISHT • Shared by Udit Vashisht

    Python’s except Quirk

    I don’t know how Alex comes up with these, but that’s a fun one :)
    ALEX BECKER

    How to Distribute a wxPython Application

    You finished up a wonderful GUI application using wxPython. How do you share it with the world? Read Mike’s article to find out.
    MIKE DRISCOLL

    Django: An Unofficial Opinionated FAQ

    KRISTIAN GLASS

    Python Standard Library Gems: collections.Counter

    IVAN SAGALAEV

    How to Use Grouping Sets in Django

    “How we cut a heavy admin dashboard response time in half with advanced SQL and some Django hackery.”
    HAKI BENITA

    Projects & Code

    OWASP/CheatSheetSeries: High Value Information on Specific Application Security Topics

    GITHUB.COM/OWASP

    orm: An Async ORM

    GITHUB.COM/ENCODE

    namedzip: Extends zip() and itertools.zip_longest() to Generate Named Tuples

    GITHUB.COM/ERBERLIN

    transistor: A Python Web Scraping Framework for Structured Web Pages

    GITHUB.COM/BOMQUOTE

    instaviz: Instant Visualization of Python AST and Code Objects

    ANTHONY SHAW

    Events

    PyData Bristol Meetup

    March 21, 2019
    MEETUP.COM

    Python Northwest

    March 21, 2019
    PYNW.ORG.UK

    PyLadies Dublin

    March 21, 2019
    PYLADIES.COM

    IndyPy Automate Conf 2019

    March 22 to March 23, 2019
    INDYPY.ORG

    PyCon SK 2019

    March 22 to March 25, 2019
    PYCON.SK

    Inland Empire Pyladies (CA, USA)

    March 25, 2019
    MEETUP.COM


    Happy Pythoning!
    This was PyCoder’s Weekly Issue #360.
    View in Browser »

    alt

    [ Subscribe to 🐍 PyCoder’s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]

    March 19, 2019 07:30 PM UTC


    Mike Driscoll

    How to Distribute a wxPython Application

    Let’s say you finished up a wonderful GUI application using wxPython. How do you share it with the world? This is always the dilemma when you finish an amazing program. Fortunately, there are several ways you can share your code. If you want to share your code with other developers, than Github or a similar website is definitely a good way to do. I won’t be covering using Git or Mercurial here. Instead what you will learn here is how to turn your application into an executable.

    By turning your code into an executable, you can allow a user to just download the binary and run it without requiring them to download Python, your source code and your dependencies. All of those things will be bundled up into the executable instead.

    There are many tools you can use to generate an executable:

    You will be using PyInstaller in this tutorial. The main benefit to using PyInstaller is that it can generate executables for Windows, Mac and Linux. Note that it does not support cross-compiling. What that means is that you cannot run PyInstaller on Linux to create a Windows executable. Instead, PyInstaller will only create an executable for the OS that it is ran on. In other words, if you run PyInstaller on Windows, it will create a Windows executable only.


    Installing PyInstaller

    Installing the PyInstaller package is nice and straightforward. All you need is pip.

    Here is how you would install PyInstaller to your system Python:

    pip install pyinstaller

    You could also install PyInstaller to a virtual Python environment using Python’s venv module or the virtualenv package.


    Generating an Executable

    The nice thing about PyInstaller is that it is very easy to use out of the box. All you need to do is run the `pyinstaller` command followed by the path to the main file of the application that you want to convert to an executable.

    Here is a non-working example:

    pyinstaller path/to/main/script.py

    If the PyInstaller application is not found, you may have to specify a full path to it. By default, PyInstaller installs to Python’s **Scripts** sub-folder, which is going to be in your system Python folder or in your virtual environment.

    Let’s take one of the simple applications from my upcoming book and turn it into an executable. For example, you could use image_viewer_slideshow.py from chapter 3:

    # image_viewer_slideshow.py
     
    import glob
    import os
    import wx
     
    class ImagePanel(wx.Panel):
     
        def __init__(self, parent):
            super().__init__(parent)
            self.max_size = 240
            self.photos = []
            self.current_photo = 0
            self.total_photos = 0
            self.layout()
     
            self.slideshow_timer = wx.Timer(self)
            self.Bind(wx.EVT_TIMER, self.on_next, self.slideshow_timer)
     
        def layout(self):
            """
            Layout the widgets on the panel
            """
     
            self.main_sizer = wx.BoxSizer(wx.VERTICAL)
            btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
     
            img = wx.Image(self.max_size, self.max_size)
            self.image_ctrl = wx.StaticBitmap(self, wx.ID_ANY, 
                                                 wx.Bitmap(img))
            self.main_sizer.Add(self.image_ctrl, 0, wx.ALL|wx.CENTER, 5)
            self.image_label = wx.StaticText(self, label="")
            self.main_sizer.Add(self.image_label, 0, wx.ALL|wx.CENTER, 5)
     
            btn_data = [("Previous", btn_sizer, self.on_previous),
                        ("Slide Show", btn_sizer, self.on_slideshow),
                        ("Next", btn_sizer, self.on_next)]
            for data in btn_data:
                label, sizer, handler = data
                self.btn_builder(label, sizer, handler)
     
            self.main_sizer.Add(btn_sizer, 0, wx.CENTER)
            self.SetSizer(self.main_sizer)
     
        def btn_builder(self, label, sizer, handler):
            """
            Builds a button, binds it to an event handler and adds it to a sizer
            """
            btn = wx.Button(self, label=label)
            btn.Bind(wx.EVT_BUTTON, handler)
            sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
     
        def on_next(self, event):
            """
            Loads the next picture in the directory
            """
            if not self.photos:
                return
     
            if self.current_photo == self.total_photos - 1:
                self.current_photo = 0
            else:
                self.current_photo += 1
            self.update_photo(self.photos[self.current_photo])
     
        def on_previous(self, event):
            """
            Displays the previous picture in the directory
            """
            if not self.photos:
                return
     
            if self.current_photo == 0:
                self.current_photo = self.total_photos - 1
            else:
                self.current_photo -= 1
            self.update_photo(self.photos[self.current_photo])
     
        def on_slideshow(self, event):
            """
            Starts and stops the slideshow
            """
            btn = event.GetEventObject()
            label = btn.GetLabel()
            if label == "Slide Show":
                self.slideshow_timer.Start(3000)
                btn.SetLabel("Stop")
            else:
                self.slideshow_timer.Stop()
                btn.SetLabel("Slide Show")
     
        def update_photo(self, image):
            """
            Update the currently shown photo
            """
            img = wx.Image(image, 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()
     
        def reset(self):
            img = wx.Image(self.max_size,
                           self.max_size)
            bmp = wx.Bitmap(img)
            self.image_ctrl.SetBitmap(bmp)
            self.current_photo = 0
            self.photos = []
     
     
    class MainFrame(wx.Frame):
     
        def __init__(self):
            super().__init__(None, title='Image Viewer',
                                            size=(400, 400))
            self.panel = ImagePanel(self)
            self.create_toolbar()
            self.Show()
     
        def create_toolbar(self):
            """
            Create a toolbar
            """
            self.toolbar = self.CreateToolBar()
            self.toolbar.SetToolBitmapSize((16,16))
     
            open_ico = wx.ArtProvider.GetBitmap(
                wx.ART_FILE_OPEN, wx.ART_TOOLBAR, (16,16))
            openTool = self.toolbar.AddTool(
                wx.ID_ANY, "Open", open_ico, "Open an Image Directory")
            self.Bind(wx.EVT_MENU, self.on_open_directory, openTool)
     
            self.toolbar.Realize()
     
        def on_open_directory(self, event):
            """
            Open a directory dialog
            """
            with wx.DirDialog(self, "Choose a directory",
                              style=wx.DD_DEFAULT_STYLE) as dlg:
     
                if dlg.ShowModal() == wx.ID_OK:
                    self.folderPath = dlg.GetPath()
     
                    photos = glob.glob(os.path.join(self.folderPath, '*.jpg'))
                    self.panel.photos = photos
                    if photos:
                        self.panel.update_photo(photos[0])
                        self.panel.total_photos = len(photos)
                    else:
                        self.panel.reset()
     
     
    if __name__ == '__main__':
        app = wx.App(redirect=False)
        frame = MainFrame()
        app.MainLoop()

    If you wanted to turn it into an executable, you would run the following:

    pyinstaller image_viewer_slideshow.py

    Make sure that when you run this command, your current working directory is the one that contains the script you are converting to an executable. PyInstaller will be creating its output in whatever the current working directory is.

    When you run this command, you should see something like this in your terminal:

    PyInstaller will create two folders in the same folder as the script that you are converting called **dist** and **build**. The **dist** folder is where you will find your executable if PyInstaller completes successfully. There will be many other files in the **dist** folder besides your executable. These are files that are required for your executable to run.

    Now let’s try running your newly created executable. When I ran my copy, I noticed that a terminal / console was appearing behind my application.

    Image Viewer with Console in Background

    This is normal as the default behavior of PyInstaller is to build your application as if it were a command-line application, not a GUI.

    You will need to add the –noconsole flag to remove the console:

    pyinstaller image_viewer_slideshow.py --noconsole

    Now when you run the result, you should no longer see a console window appearing behind your application.

    It can be complicated to distribute lots of files, so PyInstaller has another command that you can use to bundle everything up into a single executable. That command is `–onefile`. As an aside, a lot of the commands that you use with PyInstaller have shorter aliases. For example, there is a shorter alias for `–noconsole` that you can also use called: -w. Note the single dash in `-w`.

    So let’s take that information and have PyInstaller create a single file executable with no console:

    [python] pyinstaller image_viewer_slideshow.py --onefile -w

    You should now have just one file in the dist folder.


    The spec file

    PyInstaller has the concept of specification files. They are kind of like a setup.py script, which is something that you use with Python’s distutils. These spec files tell PyInstaller how to build your executable. PyInstaller will generate one for you automatically with the same name as the passed in script, but with a .spec extension. So if you passed in image_viewer_slideshow.py, then you should see a image_viewer_slideshow.spec file after running PyInstaller. This spec file will be created in the same location as your application file.

    Here is the contents of the spec file that was created from the last run of PyInstaller above:

    # -*- mode: python -*-
     
    block_cipher = None
     
     
    a = Analysis(['image_viewer.py'],
                 pathex=['C:\\Users\\mdriscoll\\Documents\\test'],
                 binaries=[],
                 datas=[],
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher,
                 noarchive=False)
    pyz = PYZ(a.pure, a.zipped_data,
                 cipher=block_cipher)
    exe = EXE(pyz,
              a.scripts,
              a.binaries,
              a.zipfiles,
              a.datas,
              [],
              name='image_viewer',
              debug=False,
              bootloader_ignore_signals=False,
              strip=False,
              upx=True,
              runtime_tmpdir=None,
              console=False )

    While PyInstaller worked fine with the image viewer example, you may find that it won’t work out of the box if you had other dependencies, such as NumPy or Pandas. If you run into issues with PyInstaller, it has very verbose logs that you can use to help you figure out the issue. One good location is the `build/cli/warn-cli.txt` file. You may also want to rebuild without the `-w` command so that you can see what is being printed to stdout in the console window.

    There are also options for changing the log level during building that may help you uncover issues.

    If none of those work, try Google or go to PyInstaller’s support page and get help there.


    Creating Executables for Mac

    While the same commands should work on Mac OSX as it does on Windows, I found that I needed to run the following command to generate a working executable:

    pyinstaller image_viewer_slideshow.py --windowed

    The output that PyInstaller generates will be slightly different and the result is an application file.

    Another popular option for generating applications on Mac is a Python package called py2app.


    Creating Executables for Linux

    For Linux, it is usually recommended that you build the executable with an old version of glibc because the newer glibc versions are backwards compatible. By building with an old version of Linux, you can usually target a wider variety of Linux versions. But your mileage may vary.

    After the files are generated, you can just tar them up into a gzipped tarball (.tax.gz). You could even using the archiving application you created in this book to do that for you, if you wanted.

    An alternative would be to learn how to create a .deb or related file that most Linux versions can install.


    Learning More About PyInstaller

    This article is not meant to be an in-depth guide to PyInstaller. It will likely change much faster than wxPython, so it is recommended that you read the documentation for PyInstaller instead. It will always be the most up-to-date location to get the information you need on the project.


    What About Installers?

    Windows users know that most of the time you have an installer application that you can run to install your application on your computer and put some shortcuts here and there. There are several useful free programs that you can use to create a Windows Installer as well as some paid ones

    Here are the two freeware applications I see mentioned the most:

    I have used Inno Setup to create a Windows installer on several occasions. It is easy to use and requires only a little reading of its documentation to get it working. I haven’t used NSIS before, but I suspect it is quite easy to use as well.

    Let’s use Inno Setup as an example and see how to generate an installer with it.


    Creating an Installer with Inno Setup

    Inno Setup is a nice freeware application that you can use to create professional looking installer programs. It works on most versions of Windows. I personally have used it for quite a few years. While Inno Setup is not open source, it is still a really nice program. You will need to download and install it from there website.

    Once installed, you can use this tool to create an installer for the executable you created earlier in this chapter.

    To get started, just run Inno Setup and you should see the following:

    Inno Setup’s Startup Page

    While Inno Setup defaults to opening an existing file, what you want to do is choose the second option from the top: “Create a new script file using the Script Wizard”. Then press **OK**.

    You should now see the first page of the Inno Setup Script Wizard. Just hit **Next** here since there’s nothing else you can really do.

    Now you should see something like this:

    Inno Setup Script Wizard Application Information Page

    This is where you enter your applications name, its version information, the publisher’s name and the application’s website. I pre-filled it with some examples, but you can enter whatever you want to here.

    Go ahead and press Next and you should see page 3:

    Inno Setup Script Wizard Application Folder Page

    This page of the wizard is where you can set the application’s install directory. On Windows, most applications install to **Program Files**, which is also the default here. This is also where you set the folder name for your application. This is the name of the folder that will appear in Program Files. Alternatively, you can check the box at the bottom that indicates that your application doesn’t need a folder at all.

    Let’s go to the next page:

    Inno Setup Script Wizard Application Files Page

    Here is where you will choose the main executable file. In this case, you want to choose the executable you created with PyInstaller. If you didn’t create the executable using the –onefile flag, then you can add the other files using the Add file(s)… button. If your application requires any other special files, like a SQLite database file or images, this is also where you would want to add them.

    By default, this page will allow the user to run your application when the installer finishes. A lot of installers do this, so it’s actually expected by most users.

    Let’s continue:

    Inno Setup Script Wizard Application Shortcuts Page

    This is the Application Shortcuts page and it allows you to manage what shortcuts are created for your application and where they should go. The options are pretty self-explanatory. I usually just use the defaults, but you are welcome to change them however you see fit.

    Let’s find out what’s on the documentation page:

    Inno Setup Script Wizard Application Documentation Page

    The Documentation Page of the wizard is where you can add your application’s license file. For example, if you were putting out an open source application, you can add the GPL or MIT or whatever license file you need there. If this were a commercial application, this is where you would add your End-Users License Agreement (EULA) file.

    Let’s see what’s next:

    Inno Setup Script Wizard Setup Languages Page

    Here you can set up which setup languages should be included. Inno Setup supports quite a few languages, with English as the default choice.

    Now let’s find out what compiler settings are:

    Inno Setup Script Wizard Compiler Settings Page

    The Compiler Settings page let’s you name the output setup file, which defaults to simply **setup**. You can set the output folder here, add a custom setup file icon and even add password protection to the setup file. I usually just leave the defaults alone, but this is an opportunity to add some branding to the setup if you have a nice icon file handy.

    The next page is for the preprocessor:

    Inno Setup Script Wizard Preprocessor Page

    The preprocessor is primarily for catching typos in the Inno Setup script file. It basically adds some helpful options at compile time to your Inno Setup script.

    Check out the documentation for full details.

    Click Next and you should see the last page of the wizard:

    Inno Setup Script Wizard End Page

    Click Finish and Inno Setup will generate an Inno Setup Script (.iss) file. When it is finished, it will ask you if you would like to compile the file.

    Go ahead and accept that dialog and you should see the following:

    Inno Setup Script

    This is the Inno Setup Script editor with your newly generated script pre-loaded into it. The top half is the script that was generated and the bottom half shows the compiler’s output. In this screenshot, it shows that the setup file was generated successfully but it also displays a warning that you might want to rename the setup file.

    At this point, you should have a working installer executable that will install your program and any files it depends on to the right locations. It will also create shortcuts in the Windows Start menu and whichever other locations you specified in the wizard.

    The script file itself can be edited. It is just a text file and the syntax is well documented on Inno Setup’s website.


    Code Signing

    Windows and Mac OSX prefer that applications are signed by a corporation or the developer. Otherwise you will see a warning that you are using an unsigned piece of code or software. The reason this matters is that it protects your application from being modified by someone else. You can think of code signing as a kind of embedded MD5 hash in your application. A signed application can be traced back to whomever signed it, which makes it more trust-worthy.

    If you want to sign code on Mac OSX, you can use XCode

    Windows has several options for signing their code. Here is a URL for getting your application certified for Windows

    You can also purchase a certificate from various companies that specialize in code signing, such as digicert.

    There is also the concept of self-signed certificates, but that is not for production or for end users. You would only self-sign for internal testing, proof-of-concept, etc. You can look up how to do that on your own.


    Wrapping Up

    You have now learned how to generate executables using PyInstaller on Windows, Mac and Linux. The command to generate the executable is the same across all platforms. While you cannot create a Windows executable by running PyInstaller on Linux, it is still quite useful for creating executable for the target operating system.

    You also learned how to use Inno Setup to create an installer for Windows. You can now use these skills to create executables for your own applications or for some of the other applications that you created in this book!


    Further Reading

    March 19, 2019 05:15 PM UTC


    Django Weblog

    2018 Malcolm Tredinnick Memorial Prize awarded to Kojo Idrissa

    The Board of the Django Software Foundation is pleased to announce that the 2018 Malcolm Tredinnick Memorial Prize has been awarded to Kojo Idrissa.

    Kojo has been active in the Django community since at least 2015, if not earlier. He's been a DjangoCon US organizer since 2016, former DEFNA board member, and current DEFNA North American Ambassador.

    Kojo has hosted an orientation for first-time DjangoCon US attendees for the last several years, which could not be a better example of Malcolm's friendly spirit to new users.

    Ken Whitesell, who nominated Kojo, also noted many Kojo's other contributions:

    Kojo is a very active member of the weekly CodeNewbie chats. Hosts the DjangoCon new-user orientation session. Very visible presence at DjangoCon, always seems to be focused on ensuring first time attendees have the best possible experience.

    The other nominees this year were:

    Every year we receive many nominations and it's always hard to pick the winner. In fact, some have been nominated in multiple years. Malcolm would be very proud of the legacy he has fostered in our community!

    Congratulations Kojo on the well deserved honor!

    March 19, 2019 04:04 PM UTC


    Real Python

    Python Decorators 101

    In this course on Python decorators, you’ll learn what they are and how to create and use them. Decorators provide a simple syntax for calling higher-order functions in Python. By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.


    [ 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 ]

    March 19, 2019 02:00 PM UTC


    Abhijeet Pal

    Starting A Django Project

    Django is one of the most popular open source full-stack web development Framework written in Python. Django is a framework for perfectionists with deadlines, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel.

    To know more about Django read: Django – Web Framework For Perfectionists

    In this article, we will go over the steps for creating and running a Django Project.

    Creating A Django Project

    A project is a collection of settings for an instance of Django including database configuration, Django-specific options, and application-specific settings.

    Before creating a Django project make sure you have Python and Django installed in your machine if not go through How To Install Django

    It is recommended to create projects in virtual environments though it’s optional using them will save you from a lot of headaches in the future. Read the following article to know why virtual environments are so important: How To A Create Virtual Environment for Python

    Note that, I am assuming that you have activated your virtual environment where your Django installation exists. Next, run the below command.

    django-admin startproject mysite

    This command will invoke the django-admin.py script, which will set up a new Django project called mysite. A Django project name can be composed of numbers, letters, or underscores. A project name cannot start with a number, it can only start with a letter or underscore in addition special characters and spaces aren’t allowed anywhere in a project name.

    You’ll now notice within your workspace there is a directory set to the name of your new project, mysite. Inside the directory, there is another directory with the same name as the project and a python script named manage.py

    Inside the second level project directory, there are another 4 Python scripts. So the default Django project can be illustrated as follows.

    mysite/
       manage.py
       mysite/
          __init__.py
          settings.py
          urls.py
          wsgi.py

    __init__.py –  a blank Python script whose presence indicates to the Python interpreter that the directory is a Python package. This file allows Python packages to be imported from the directories they are present.

    settings.py – Contains the configuration settings for the Django project.

    urls.py – Contains URL patterns for the Django project.

    wsgi.py – Contains WSGI configuration properties for the Django project. Basically, Python script used to help run your development server and deploy your project to a production environment.

    manage.py –  a command-line utility that lets you interact with your Django project in many ways. This script is responsible for all project specific tasks.

    Note that, there are two directories with the project name, this might seem confusing at first however you can always change the name of the outer directory which occasionally referred to as the Base Directory. The second level project directory is hardcoded in some of the Django specific files so better not mess with it.

    Running A Django Project

    Now that we have created a Django project we can see it in action in the browser. Django comes with a built-in web server for development. Navigate to the Base directory where manage.py is, and run the below command.

    python manage.py runserver

    Ignore all the migration errors for the moment, Now open your preferred browser and go to http://127.0.0.1:8000/ If everything went right you should see the default the page of Django.Starting A Django Project

    To stop the server press ctrl + c in the terminal window. Running the application on a different port is also possible you just need to pass the port number along with the command.

    # Run the development server on the local address and port 4345 (http://127.0.0.1:4345/)
    python manage.py runserver 4345
    
    # Run the dev server on the 96.126.104.88 address and port 80 (http://96.126.104.88/)
    python manage.py runserver 96.126.104.88:80

    The post Starting A Django Project appeared first on Django Central.

    March 19, 2019 12:11 PM UTC


    Shyama Sankar Vellore

    Python Tuples: Cheat Sheet

    A cheat sheet for tuples in Python. What are tuples? How are they used in Python?


    Jump to the cheat sheet
    Similar to lists, tuples are another example of a 'sequence'  datatype in Python. Some key points:
    • A tuple contains an ordered collection of values or items.
    • Tuples are defined as a comma-separated list of items (usually enclosed within parenthesis).
    • They can also be constructed using the tuple() constructor. It takes any sequence as its input.
    • They can contain elements of the same or different data types.
    • Items in a tuple can be accessed by unpacking or indexing.
    • Elements of a tuple are indexed from 0 to length-1.
    • Tuples are immutable, i.e., once the tuple is created, we cannot change its contents.
    • We cannot assign values to elements of tuples by indexing them. Neither does it support methods like append(), insert(), delete(), etc. which are typically used for mutating collections.
    • Tuples support sequence unpacking, i.e., its elements can be unpacked to individual variables.

    Tuples: Cheatsheet

    Useful Resources and References

    March 19, 2019 06:56 AM UTC


    leftmouseclickin

    Plotting the average directional movement index rating line with python

    Our Own Score

    In this chapter, we will create the plot adxr method in the ongoing Forex and Stock application project to plot the average directional movement index rating line. The Average Directional Movement Index Rating (ADXR) measures the strength of the Average Directional Movement Index (ADX). It’s calculated by taking the average of the current ADX and the ADX from one time period before (time periods can vary, but the most typical period used is 14 days).

    Below is the modified version of the program. We have included a new plot adxr method as well as the plot adxr button which will be used to call the plot adxr method.

    import json
    from tkinter import *
    import tkinter.ttk as tk
    from alpha_vantage.foreignexchange import ForeignExchange
    from alpha_vantage.techindicators import TechIndicators
    from alpha_vantage.timeseries import TimeSeries
    import matplotlib.pyplot as plt
    from alpha_vantage.sectorperformance import SectorPerformances
    
    win = Tk() # Create tk instance
    win.title("Real Forex n Stock") # Add a title
    win.resizable(0, 0) # Disable resizing the GUI
    win.configure(background='white') # change window background color
    
    selectorFrame = Frame(win, background="white") # create the top frame to hold base and quote currency combobox
    selectorFrame.pack(anchor = "nw", pady = 2, padx=10)
    currency_label = Label(selectorFrame, text = "Select base currency / quote currency :", background="white")
    currency_label.pack(anchor="w") # the currency pair label
    
    selector1Frame = Frame(win, background="white") # create the middle frame to hold base and quote currency combobox
    selector1Frame.pack(anchor = "nw", pady = 2, padx=10)
    stock_label = Label(selector1Frame, text = "Select Stock / Time Interval / Series type / Moving average type / Fast Period / Slow Period :", background="white")
    stock_label.pack(anchor="w") # the stock label
    
    curr1 = tuple() # the tuple which will be populated by base and quote currency
    currency_list = ['AUD', 'BCH', 'BNB', 'BND', 'BTC', 'CAD', 'CHF', 'CNY', 'EOS', 'EUR', 'ETH', 'GBP', 'HKD', 'JPY', 'LTC', 'NZD', 'MYR', 'TRX', 'USD', 'USDT', 'XLM', 'XRP'] # major world currency pairs
    
    # populate the combo box for both the base and quote currency
    for key in currency_list:
        curr1 += (key, )
    
    # populate the stock symbol tuple
    f = open("stock.txt", "r")
    curr2 = tuple()
    for line in f.readlines():
        curr2 += (line.replace('\n', ''),)
    f.close()
    
    # Create a combo box for base currency
    base_currency = StringVar() # create a string variable
    based = tk.Combobox(selectorFrame, textvariable=base_currency)
    based['values'] = curr1
    based.pack(side = LEFT, padx=3)
    
    # Create a combo box for quote currency
    quote_currency = StringVar() # create a string variable
    quote = tk.Combobox(selectorFrame, textvariable=quote_currency)
    quote['values'] = curr1
    quote.pack(side = LEFT, padx=3)
    
    # Create a combo box for stock items
    stock_symbol = StringVar() # create a string variable
    stock = tk.Combobox(selector1Frame, textvariable=stock_symbol)
    stock['values'] = curr2
    stock.current(0)
    stock.pack(side = LEFT, padx=3)
    
    interval = tk.Combobox(selector1Frame)
    interval['values'] = ('1min', '5min', '15min', '30min', '60min', 'daily', 'weekly', 'monthly')
    interval.current(0)
    interval.pack(side = LEFT, padx=3)
    
    price_type = tk.Combobox(selector1Frame)
    price_type['values'] = ('close', 'open', 'high', 'low')
    price_type.current(0)
    price_type.pack(side =LEFT, padx=3)
    
    matype_type = tk.Combobox(selector1Frame, width=37)
    matype_type['values'] = ('Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)')
    matype_type.current(0)
    matype_type.pack(side =LEFT, padx=3)
    mattype_list = ['Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)']
    
    # fill up the fast period and slow period combo boxes with integer ranging from 2 to 10,000
    fa = tuple()
    for i in range(2, 10001):
        fa += (i, )
    
    fast_pe = tk.Combobox(selector1Frame)
    fast_pe['values'] = fa
    fast_pe.current(0)
    fast_pe.pack(side=LEFT, padx=3)
    
    slow_pe = tk.Combobox(selector1Frame)
    slow_pe['values'] = fa
    slow_pe.current(0)
    slow_pe.pack(side=LEFT, padx=3)
    
    # create text widget area
    s = StringVar() # create string variable which will be used to fill up the Forex or stock data
    # create currency frame and text widget to display the incoming forex data
    currencyFrame = Frame(win)
    currencyFrame.pack(side=TOP, fill=X)
    currency = Label(currencyFrame)
    currency.pack(fill=X)
    text_widget = Text(currency, fg='white', background='black')
    text_widget.pack(fill=X)
    s.set("Click the find button to find out the currency exchange rate")
    text_widget.insert(END, s.get())
    
    buttonFrame = Frame(win) # create a bottom frame to hold the find button
    buttonFrame.pack(side = BOTTOM, fill=X, pady = 6, padx=10)
    
    # first get the api key and secret from the file
    f = open("alpha.txt", "r")
    api_key = f.readline()
    f.close()
    api_key = api_key.replace('\n', '')
    
    def get_exchange_rate(): # this method will display the incoming forex data after the api called
    
        try:
            cc = ForeignExchange(key= api_key)
            from_ = based.get()
            to_ = quote.get()
    
            countVar = StringVar()  # use to hold the character count
            text_widget.tag_remove("search", "1.0", "end")  # cleared the hightlighted currency pair
    
            if(from_ != '' and to_ != '' and from_ != to_):
                data, _ = cc.get_currency_exchange_rate(from_currency=from_, to_currency=to_)
                exchange_rate = dict(json.loads(json.dumps(data)))
                count = 1
                sell_buy = str(count) + ".) Pair : " + exchange_rate['1. From_Currency Code'] + "(" + exchange_rate['2. From_Currency Name'] + ")" + " / " + exchange_rate['3. To_Currency Code']+"(" + exchange_rate['4. To_Currency Name'] + ") : "  + str(exchange_rate['5. Exchange Rate']) + '\n'
                text_widget.delete('1.0', END)  # clear all those previous text first
                s.set(sell_buy)
                text_widget.insert(INSERT, s.get())  # display forex rate in text widget
                pos = text_widget.search(from_, "1.0", stopindex="end", count=countVar)
                text_widget.tag_configure("search", background="green")
                end_pos = float(pos) + float(0.7)
                text_widget.tag_add("search", pos, str(end_pos))  # highlight the background of the searched currency pair
                pos = float(pos) + 2.0
                text_widget.see(str(pos))
    
        except:
            print("An exception occurred")
    
    def plot_stock_echange():
    
        try:
            stock_symbol_text = stock.get() # get the selected symbol
            if(stock_symbol_text!= ''):
                ts = TimeSeries(key=api_key, output_format='pandas')
                data, meta_data = ts.get_intraday(symbol=stock_symbol_text, interval='1min', outputsize='full')
                data['4. close'].plot()
                stock_title = 'Intraday Times Series for the ' + stock_symbol_text + ' stock (1 min)'
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_stock_technical():
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_bbands(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'BBbands indicator for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_op(): # plot the Absolute price oscillator (APO)
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_apo(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), fastperiod = fast_pe.get(), slowperiod= slow_pe.get())
                data.plot()
                stock_title = 'Absolute Price Oscillator (APO) for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An exception occurred")
    
    def plot_adxr(): # plot the average directional movement index rating
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_adxr(symbol=stock_symbol_text, interval=interval.get(), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'Average directional movement index rating for ' + stock_symbol_text + ' at ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An exception occurred")
    
    def plot_sector_performance():
    
        sp = SectorPerformances(key=api_key, output_format='pandas')
        data, meta_data = sp.get_sector()
        data['Rank A: Real-Time Performance'].plot(kind='bar')
        plt.title('Real Time Performance (%) per Sector')
        plt.tight_layout()
        plt.grid()
        plt.show()
    
    def plot_ad():
    
        try:
            stock_symbol_text = stock.get()  # get the selected stock symbol
            if (stock_symbol_text != ''):
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_ad(symbol=stock_symbol_text, interval=interval.get())
                data.plot()
                stock_title = 'Chaikin A/D line values for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    action_vid = tk.Button(buttonFrame, text="Calculate Exchange Rate", command=get_exchange_rate) # button used to find out the exchange rate of currency pair
    action_vid.pack(side=LEFT, padx=2)
    action_stock_plot = tk.Button(buttonFrame, text="Plot Stock", command=plot_stock_echange) # button used to plot the intra-minute stock value
    action_stock_plot.pack(side=LEFT, padx=2)
    action_technical_plot = tk.Button(buttonFrame, text="Plot Technical", command=plot_stock_technical) # button used to plot the 60 minutes stock technical value
    action_technical_plot.pack(side=LEFT, padx=2)
    action_sector_plot = tk.Button(buttonFrame, text="Plot Sector Performance", command=plot_sector_performance) # button used to plot the sector performance graph
    action_sector_plot.pack(side=LEFT, padx=2)
    action_ad_plot = tk.Button(buttonFrame, text="Plot AD Line", command=plot_ad) # button used to plot the A/D line graph
    action_ad_plot.pack(side=LEFT, padx=2)
    action_ad_op = tk.Button(buttonFrame, text="Plot APO Line", command=plot_op) # button used to plot the APO line graph
    action_ad_op.pack(side=LEFT, padx=3)
    action_adxr = tk.Button(buttonFrame, text="Plot ADXR Line", command=plot_adxr) # button used to plot the average directional movement index rating
    action_adxr.pack(side=LEFT, padx=3)
    win.iconbitmap(r'ico.ico')
    win.mainloop()
    

    As usual run the program and then click on the plot adxr button we will see this outcome.

    March 19, 2019 04:12 AM UTC


    codingdirectional

    Get only the latest live match from NBA with python

    Hello and welcome back, in this chapter we will continue to develop the previous sports score application by showing all the latest live matches from the NBA on the text widget area. The sports.py module does not have a method to only return the live NBA matches but instead that API call will return basically all the live basketball matches from all the basketball leagues around the world. Therefore we will need to filter out all those none NBA results before showing the data on the text widget. Below is the modified version of the program which will do just that. We will perform the filtering process under the get matches method.

    import sports
    import json
    from tkinter import *
    import tkinter.ttk as tk
    import datetime
    
    win = Tk() # Create tk instance
    win.title("NBA") # Add a title
    win.resizable(0, 0) # Disable resizing the GUI
    win.configure(background='white') # change window background color
    
    selectorFrame = Frame(win, background="white") # create top frame to hold team 1 vs team 2 combobox
    selectorFrame.pack(anchor = "nw", pady = 2, padx=10)
    match_label = Label(selectorFrame, text = "Select Team 1 vs Team 2 :", background="white")
    match_label.pack(anchor="w") # the team label
    
    # Create a combo box for team 1
    team1 = tk.Combobox(selectorFrame)
    team1.pack(side = LEFT, padx=3)
    
    # Create a combo box for team 2
    team2 = tk.Combobox(selectorFrame)
    team2.pack(side = LEFT, padx=3)
    
    s = StringVar() # create string variable
    # create match frame and text widget to display the incoming match data
    matchFrame = Frame(win)
    matchFrame.pack(side=TOP)
    match = Label(matchFrame)
    match.pack()
    text_widget = Text(match, fg='white', background='black')
    text_widget.pack()
    s.set("Click below buttons to find out the match result")
    text_widget.insert(END, s.get())
    
    buttonFrame = Frame(win) # create a bottom frame to hold the find button
    buttonFrame.pack(side = BOTTOM, fill=X, pady = 6)
    
    # fill up the combo boxes with the team name data from the text file
    team_tuple = tuple()
    f = open("TextFile1.txt", "r")
    nba_list = [] # will be used to filter out the unwanted team from the other league
    for line in f.readlines():
        line = line.replace('\n', '')
        nba_list.append(line)
        team_tuple += (line, )
    f.close()
    
    team1["values"] = team_tuple
    team1.current(1)
    team2["values"] = team_tuple
    team2.current(0)
    
    def get_matches(): # show all the NBA team matches
    
        match_str = '               Live NBA Matches ' + str(datetime.datetime.now()) + '\n'
    
        try:
            matches = sports.get_sport(sports.BASKETBALL)
            for item in matches:
                match_all = str(item)
                for nba_team in nba_list:
                    if(nba_team in match_all):
                        match_str += (match_all)  + '\n'
                        break
            text_widget.delete('1.0', END) # clear all those previous text first
            s.set(match_str)
            text_widget.insert(INSERT, s.get()) # display teams match data in text widget
        except:
            print("An exception occurred")
    
    def get_match(): # return the recent match of team 1 vs team 2
       
        try:
            match = sports.get_match(sports.BASKETBALL, team1.get(), team2.get())
            text_widget.delete('1.0', END) # clear all those previous text first
            s.set(match)
            text_widget.insert(INSERT, s.get()) # display team match data in text widget
        except:
            print("An exception occurred")
    
    action_vid = tk.Button(buttonFrame, text="Latest Match", command=get_match) # button used to find out the team match data
    action_vid.pack(side=LEFT, padx=2)
    action_vid1 = tk.Button(buttonFrame, text="All Matches", command=get_matches) # button used to find out the teams match data
    action_vid1.pack(side=LEFT, padx=2)
    
    win.mainloop()
    

    If you start the software and click on the All Matches button you will see all the live matches from NBA in the text widget area. Like, share or follow me on Twitter.

    Download mine latest Free Firefox Extension on Firefox Store to show your love for my project.

    Due to the tight daily schedule, this site will switch to twice a week updating starting from today onward.

    March 19, 2019 03:23 AM UTC

    March 18, 2019


    Python Insider

    Python 3.4.10 is now available

    Python 3.4.10 is now available.  You can download it here.

    Python 3.4.10 is the final release in the Python 3.4 series.  As of this release, the 3.4 branch has been retired, no further changes to 3.4 will be accepted, and no new releases will be made.  This is standard Python policy; Python releases get five years of support and are then retired.

    If you're still using Python 3.4, you should consider upgrading to the current version--3.7.2 as of this writing.  Newer versions of Python have many new features, performance improvements, and bug fixes, which should all serve to enhance your Python programming experience.

    We in the Python core development community thank you for your interest in 3.4, and we wish you all the best!

    March 18, 2019 04:37 PM UTC

    Python 3.5.7 is now available

    Python 3.5.7 is now available.  You can download Python 3.5.7 here.

    March 18, 2019 04:36 PM UTC


    leftmouseclickin

    Plotting Absolute Price Oscillator (APO) Line with Python

    Our Own Score

    If you make a search on Google about APO Line, this is what you will see: Absolute Price Oscillator (APO) moving averages of a security’s price and is expressed as an absolute value. APO crossing above zero is considered bullish while crossing below zero is bearish.

    This is the line we are going to plot with the help of the alpha vantage module. Below is the edit version of the Forex and Stock application. The new plot op method will plot the APO line after we have clicked on the Plot APO Line button. Just like the BBbands indicator line we can include various parameters in the get_apo method.

    import json
    from tkinter import *
    import tkinter.ttk as tk
    from alpha_vantage.foreignexchange import ForeignExchange
    from alpha_vantage.techindicators import TechIndicators
    from alpha_vantage.timeseries import TimeSeries
    import matplotlib.pyplot as plt
    from alpha_vantage.sectorperformance import SectorPerformances
    
    win = Tk() # Create tk instance
    win.title("Real Forex n Stock") # Add a title
    win.resizable(0, 0) # Disable resizing the GUI
    win.configure(background='white') # change window background color
    
    selectorFrame = Frame(win, background="white") # create the top frame to hold base and quote currency combobox
    selectorFrame.pack(anchor = "nw", pady = 2, padx=10)
    currency_label = Label(selectorFrame, text = "Select base currency / quote currency :", background="white")
    currency_label.pack(anchor="w") # the currency pair label
    
    selector1Frame = Frame(win, background="white") # create the middle frame to hold base and quote currency combobox
    selector1Frame.pack(anchor = "nw", pady = 2, padx=10)
    stock_label = Label(selector1Frame, text = "Select Stock / Time Interval / Series type / Moving average type / Fast Period / Slow Period :", background="white")
    stock_label.pack(anchor="w") # the stock label
    
    curr1 = tuple() # the tuple which will be populated by base and quote currency
    currency_list = ['AUD', 'BCH', 'BNB', 'BND', 'BTC', 'CAD', 'CHF', 'CNY', 'EOS', 'EUR', 'ETH', 'GBP', 'HKD', 'JPY', 'LTC', 'NZD', 'MYR', 'TRX', 'USD', 'USDT', 'XLM', 'XRP'] # major world currency pairs
    
    # populate the combo box for both the base and quote currency
    for key in currency_list:
        curr1 += (key, )
    
    # populate the stock symbol tuple
    f = open("stock.txt", "r")
    curr2 = tuple()
    for line in f.readlines():
        curr2 += (line.replace('\n', ''),)
    f.close()
    
    # Create a combo box for base currency
    base_currency = StringVar() # create a string variable
    based = tk.Combobox(selectorFrame, textvariable=base_currency)
    based['values'] = curr1
    based.pack(side = LEFT, padx=3)
    
    # Create a combo box for quote currency
    quote_currency = StringVar() # create a string variable
    quote = tk.Combobox(selectorFrame, textvariable=quote_currency)
    quote['values'] = curr1
    quote.pack(side = LEFT, padx=3)
    
    # Create a combo box for stock items
    stock_symbol = StringVar() # create a string variable
    stock = tk.Combobox(selector1Frame, textvariable=stock_symbol)
    stock['values'] = curr2
    stock.current(0)
    stock.pack(side = LEFT, padx=3)
    
    interval = tk.Combobox(selector1Frame)
    interval['values'] = ('1min', '5min', '15min', '30min', '60min', 'daily', 'weekly', 'monthly')
    interval.current(0)
    interval.pack(side = LEFT, padx=3)
    
    price_type = tk.Combobox(selector1Frame)
    price_type['values'] = ('close', 'open', 'high', 'low')
    price_type.current(0)
    price_type.pack(side =LEFT, padx=3)
    
    matype_type = tk.Combobox(selector1Frame, width=37)
    matype_type['values'] = ('Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)')
    matype_type.current(0)
    matype_type.pack(side =LEFT, padx=3)
    mattype_list = ['Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)']
    
    # fill up the fast period and slow period combo boxes with integer ranging from 2 to 10,000
    fa = tuple()
    for i in range(2, 10001):
        fa += (i, )
    
    fast_pe = tk.Combobox(selector1Frame)
    fast_pe['values'] = fa
    fast_pe.current(0)
    fast_pe.pack(side=LEFT, padx=3)
    
    slow_pe = tk.Combobox(selector1Frame)
    slow_pe['values'] = fa
    slow_pe.current(0)
    slow_pe.pack(side=LEFT, padx=3)
    
    # create text widget area
    s = StringVar() # create string variable which will be used to fill up the Forex data
    # create currency frame and text widget to display the incoming forex data
    currencyFrame = Frame(win)
    currencyFrame.pack(side=TOP, fill=X)
    currency = Label(currencyFrame)
    currency.pack(fill=X)
    text_widget = Text(currency, fg='white', background='black')
    text_widget.pack(fill=X)
    s.set("Click the find button to find out the currency exchange rate")
    text_widget.insert(END, s.get())
    
    buttonFrame = Frame(win) # create a bottom frame to hold the find button
    buttonFrame.pack(side = BOTTOM, fill=X, pady = 6, padx=10)
    
    # first get the api key and secret from the file
    f = open("alpha.txt", "r")
    api_key = f.readline()
    f.close()
    api_key = api_key.replace('\n', '')
    
    def get_exchange_rate(): # this method will display the incoming forex data after the api called
    
        try:
            cc = ForeignExchange(key= api_key)
            from_ = based.get()
            to_ = quote.get()
    
            countVar = StringVar()  # use to hold the character count
            text_widget.tag_remove("search", "1.0", "end")  # cleared the hightlighted currency pair
    
            if(from_ != '' and to_ != '' and from_ != to_):
                data, _ = cc.get_currency_exchange_rate(from_currency=from_, to_currency=to_)
                exchange_rate = dict(json.loads(json.dumps(data)))
                count = 1
                sell_buy = str(count) + ".) Pair : " + exchange_rate['1. From_Currency Code'] + "(" + exchange_rate['2. From_Currency Name'] + ")" + " / " + exchange_rate['3. To_Currency Code']+"(" + exchange_rate['4. To_Currency Name'] + ") : "  + str(exchange_rate['5. Exchange Rate']) + '\n'
                text_widget.delete('1.0', END)  # clear all those previous text first
                s.set(sell_buy)
                text_widget.insert(INSERT, s.get())  # display forex rate in text widget
                pos = text_widget.search(from_, "1.0", stopindex="end", count=countVar)
                text_widget.tag_configure("search", background="green")
                end_pos = float(pos) + float(0.7)
                text_widget.tag_add("search", pos, str(end_pos))  # highlight the background of the searched currency pair
                pos = float(pos) + 2.0
                text_widget.see(str(pos))
    
        except:
            print("An exception occurred")
    
    def plot_stock_echange():
    
        try:
            stock_symbol_text = stock.get() # get the selected symbol
            if(stock_symbol_text!= ''):
                ts = TimeSeries(key=api_key, output_format='pandas')
                data, meta_data = ts.get_intraday(symbol=stock_symbol_text, interval='1min', outputsize='full')
                data['4. close'].plot()
                stock_title = 'Intraday Times Series for the ' + stock_symbol_text + ' stock (1 min)'
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_stock_technical():
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_bbands(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), time_period=int(interval.get().replace('min', '')))
                data.plot()
                stock_title = 'BBbands indicator for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    def plot_op(): # plot the Absolute price oscillator (APO)
    
        try:
            stock_symbol_text = stock.get() # get the selected stock symbol
            if(stock_symbol_text!= ''):
    
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_apo(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), fastperiod = fast_pe.get(), slowperiod= slow_pe.get())
                data.plot()
                stock_title = 'Absolute Price Oscillator (APO) for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except ValueError:
            print("An exception occurred")
    
    def plot_sector_performance():
    
        sp = SectorPerformances(key=api_key, output_format='pandas')
        data, meta_data = sp.get_sector()
        data['Rank A: Real-Time Performance'].plot(kind='bar')
        plt.title('Real Time Performance (%) per Sector')
        plt.tight_layout()
        plt.grid()
        plt.show()
    
    def plot_ad():
    
        try:
            stock_symbol_text = stock.get()  # get the selected stock symbol
            if (stock_symbol_text != ''):
                ti = TechIndicators(key=api_key, output_format='pandas')
                data, meta_data = ti.get_ad(symbol=stock_symbol_text, interval=interval.get())
                data.plot()
                stock_title = 'Chaikin A/D line values for ' + stock_symbol_text + ' ' + interval.get()
                plt.title(stock_title)
                plt.show()
        except:
            print("An exception occurred")
    
    action_vid = tk.Button(buttonFrame, text="Calculate Exchange Rate", command=get_exchange_rate) # button used to find out the exchange rate of currency pair
    action_vid.pack(side=LEFT, padx=2)
    action_stock_plot = tk.Button(buttonFrame, text="Plot Stock", command=plot_stock_echange) # button used to plot the intra-minute stock value
    action_stock_plot.pack(side=LEFT, padx=2)
    action_technical_plot = tk.Button(buttonFrame, text="Plot Technical", command=plot_stock_technical) # button used to plot the 60 minutes stock technical value
    action_technical_plot.pack(side=LEFT, padx=2)
    action_sector_plot = tk.Button(buttonFrame, text="Plot Sector Performance", command=plot_sector_performance) # button used to plot the sector performance graph
    action_sector_plot.pack(side=LEFT, padx=2)
    action_ad_plot = tk.Button(buttonFrame, text="Plot AD Line", command=plot_ad) # button used to plot the A/D line graph
    action_ad_plot.pack(side=LEFT, padx=2)
    action_ad_op = tk.Button(buttonFrame, text="Plot APO Line", command=plot_op) # button used to plot the APO line graph
    action_ad_op.pack(side=LEFT, padx=3)
    
    win.iconbitmap(r'ico.ico')
    win.mainloop()
    

    If you run the above program and then click on the ‘Plot APO Line’ button you will see the below outcome.

    Like, share or follow me on Twitter.

    March 18, 2019 02:10 PM UTC


    Real Python

    How to Build a Python GUI Application With wxPython

    There are many graphical user interface (GUI) toolkits that you can use with the Python programming language. The big three are Tkinter, wxPython, and PyQt. Each of these toolkits will work with Windows, macOS, and Linux, with PyQt having the additional capability of working on mobile.

    A graphical user interface is an application that has buttons, windows, and lots of other widgets that the user can use to interact with your application. A good example would be a web browser. It has buttons, tabs, and a main window where all the content loads.

    In this article, you’ll learn how to build a graphical user interface with Python using the wxPython GUI toolkit.

    Here are the topics covered:

    Let’s start learning!

    Free Bonus: Click here to get access to a chapter from Python Tricks: The Book that shows you Python's best practices with simple examples you can apply instantly to write more beautiful + Pythonic code.

    Getting Started With wxPython

    The wxPython GUI toolkit is a Python wrapper around a C++ library called wxWidgets. The initial release of wxPython was in 1998, so wxPython has been around quite a long time. wxPython’s primary difference from other toolkits, such as PyQt or Tkinter, is that wxPython uses the actual widgets on the native platform whenever possible. This makes wxPython applications look native to the operating system that it is running on.

    PyQt and Tkinter both draw their widgets themselves, which is why they don’t always match the native widgets, although PyQt is very close.

    This is not to say that wxPython does not support custom widgets. In fact, the wxPython toolkit has many custom widgets included with it, along with dozens upon dozens of core widgets. The wxPython downloads page has a section called Extra Files that is worth checking out.

    Here, there is a download of the wxPython Demo package. This is a nice little application that demonstrates the vast majority of the widgets that are included with wxPython. The demo allows a developer to view the code in one tab and run it in a second tab. You can even edit and re-run the code in the demo to see how your changes affect the application.

    Installing wxPython

    You will be using the latest wxPython for this article, which is wxPython 4, also known as the Phoenix release. The wxPython 3 and wxPython 2 versions are built only for Python 2. When Robin Dunn, the primary maintainer of wxPython, created the wxPython 4 release, he deprecated a lot of aliases and cleaned up a lot of code to make wxPython more Pythonic and easier to maintain.

    You will want to consult the following links if you are migrating from an older version of wxPython to wxPython 4 (Phoenix):

    The wxPython 4 package is compatible with both Python 2.7 and Python 3.

    You can now use pip to install wxPython 4, which was not possible in the legacy versions of wxPython. You can do the following to install it on your machine:

    $ pip install wxpython
    

    Note: On Mac OS X you will need a compiler installed such as XCode for the install to complete successfully. Linux may also require you to install some dependencies before the pip installer will work correctly.

    For example, I needed to install freeglut3-dev, libgstreamer-plugins-base0.10-dev, and libwebkitgtk-3.0-dev on Xubuntu to get it to install.

    Fortunately, the error messages that pip displays are helpful in figuring out what is missing, and you can use the prerequisites section on the wxPython Github page to help you find the information you need if you want to install wxPython on Linux.

    There are some Python wheels available for the most popular Linux versions that you can find in the Extras Linux section with both GTK2 and GTK3 versions. To install one of these wheels, you would use the following command:

    $ pip install -U -f https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-18.04/ wxPython
    

    Be sure you have modified the command above to match your version of Linux.

    Definition of a GUI

    As was mentioned in the introduction, a graphical user interface (GUI) is an interface that is drawn on the screen for the user to interact with.

    User interfaces have some common components:

    All of these items are known generically as widgets. There are many other common widgets and many custom widgets that wxPython supports. A developer will take the widgets and arrange them logically on a window for the user to interact with.

    Event Loops

    A graphical user interface works by waiting for the user to do something. The something is called an event. Events happen when the user types something while your application is in focus or when the user uses their mouse to press a button or other widget.

    Underneath the covers, the GUI toolkit is running an infinite loop that is called an event loop. The event loop just waits for events to occur and then acts on those events according to what the developer has coded the application to do. When the application doesn’t catch an event, it effectively ignores that it even happened.

    When you are programming a graphical user interface, you will want to keep in mind that you will need to hook up each of the widgets to event handlers so that your application will do something.

    There is a special consideration that you need to keep in mind when working with event loops: they can be blocked. When you block an event loop, the GUI will become unresponsive and appear to freeze to the user.

    Any process that you launch in a GUI that will take longer than a quarter second should probably be launched as a separate thread or process. This will prevent your GUI from freezing and give the user a better user experience.

    The wxPython framework has special thread-safe methods that you can use to communicate back to your application to let it know that the thread is finished or to give it an update.

    Let’s create a skeleton application to demonstrate how events work.

    Creating a Skeleton Application

    An application skeleton in a GUI context is a user interface with widgets that don’t have any event handlers. These are useful for prototyping. You basically just create the GUI and present it to your stakeholders for sign-off before spending a lot of time on the backend logic.

    Let’s start by creating a Hello World application with wxPython:

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

    Note: Mac users may get the following message: This program needs access to the screen. Please run with a Framework build of python, and only when you are logged in on the main display of your Mac. If you see this message and you are not running in a virtualenv, then you need to run your application with pythonw instead of python. If you are running wxPython from within a virtualenv, then see the wxPython wiki for the solution.

    In this example, you have two parts: wx.App and the wx.Frame. The wx.App is wxPython’s application object and is required for running your GUI. The wx.App starts something called a .MainLoop(). This is the event loop that you learned about in the previous section.

    The other piece of the puzzle is wx.Frame, which will create a window for the user to interact with. In this case, you told wxPython that the frame has no parent and that its title is Hello World. Here is what it looks like when you run the code:

    Hello World in wxPython

    Note: The application will look different when you run it on Mac or Windows.

    By default, a wx.Frame will include minimize, maximize, and exit buttons along the top. You won’t normally create an application in this manner though. Most wxPython code will require you to subclass the wx.Frame and other widgets so that you can get the full power of the toolkit.

    Let’s take a moment and rewrite your code as a class:

    import wx
    
    class MyFrame(wx.Frame):    
        def __init__(self):
            super().__init__(parent=None, title='Hello World')
            self.Show()
    
    if __name__ == '__main__':
        app = wx.App()
        frame = MyFrame()
        app.MainLoop()
    

    You can use this code as a template for your application. However, this application doesn’t do very much, so let’s take a moment to learn a little about some of the other widgets you could add.

    Widgets

    The wxPython toolkit has more than one hundred widgets to choose from. This allows you to create rich applications, but it can also be daunting trying to figure out which widget to use. This is why the wxPython Demo is helpful, as it has a search filter that you can use to help you find the widgets that might apply to your project.

    Most GUI applications allow the user to enter some text and press a button. Let’s go ahead and add those widgets:

    import wx
    
    class MyFrame(wx.Frame):    
        def __init__(self):
            super().__init__(parent=None, title='Hello World')
            panel = wx.Panel(self)
    
            self.text_ctrl = wx.TextCtrl(panel, pos=(5, 5))
            my_btn = wx.Button(panel, label='Press Me', pos=(5, 55))
    
            self.Show()
    
    if __name__ == '__main__':
        app = wx.App()
        frame = MyFrame()
        app.MainLoop()
    

    When you run this code, your application should look like this:

    Hello World in wxPython with widgets

    The first widget you need to add is something called wx.Panel. This widget is not required, but recommended. On Windows, you are actually required to use a Panel so that the background color of the frame is the right shade of gray. Tab traversal is disabled without a Panel on Windows.

    When you add the panel widget to a frame and the panel is the sole child of the frame, it will automatically expand to fill the frame with itself.

    The next step is to add a wx.TextCtrl to the panel. The first argument for almost all widgets is which parent the widget should go onto. In this case, you want the text control and the button to be on top of the panel, so it is the parent you specify.

    You also need to tell wxPython where to place the widget, which you can do by passing in a position via the pos parameter. In wxPython, the origin location is (0,0) which is the upper left corner of the parent. So for the text control, you tell wxPython that you want to position its top left corner 5 pixels from the left (x) and 5 pixels from the top (y).

    Then you add your button to the panel and give it a label. To prevent the widgets from overlapping, you need to set the y-coordinate to 55 for the button’s position.

    Absolute Positioning

    When you provide exact coordinates for your widget’s position, the technique that you used is called absolute positioning. Most GUI toolkits provide this capability, but it’s not actually recommended.

    As your application becomes more complex, it becomes difficult to keep track of all the widget locations and if you have to move the widgets around. Resetting all those positions becomes a nightmare.

    Fortunately all modern GUI toolkits provide a solution for this, which is what you will learn about next.

    Sizers (Dynamic Sizing)

    The wxPython toolkit includes sizers, which are used for creating dynamic layouts. They manage the placement of your widgets for you and will adjust them when you resize the application window. Other GUI toolkits will refer to sizers as layouts, which is what PyQt does.

    Here are the primary types of sizers that you will see used most often:

    Let’s add a wx.BoxSizer to your example and see if we can make it work a bit more nicely:

    import wx
    
    class MyFrame(wx.Frame):    
        def __init__(self):
            super().__init__(parent=None, title='Hello World')
            panel = wx.Panel(self)        
            my_sizer = wx.BoxSizer(wx.VERTICAL)        
            self.text_ctrl = wx.TextCtrl(panel)
            my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)        
            my_btn = wx.Button(panel, label='Press Me')
            my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)        
            panel.SetSizer(my_sizer)        
            self.Show()
    
    if __name__ == '__main__':
        app = wx.App()
        frame = MyFrame()
        app.MainLoop()
    

    Here you create an instance of a wx.BoxSizer and pass it wx.VERTICAL, which is the orientation that widgets are added to the sizer.

    In this case, the widgets will be added vertically, which means they will be added one at a time from top to bottom. You may also set a BoxSizer’s orientation to wx.HORIZONTAL. When you do that, the widgets would be added from left to right.

    To add a widget to a sizer, you will use .Add(). It accepts up to five arguments:

    The window argument is the widget to be added while proportion sets how much space relative to other widgets in the sizer this particular widget should take. By default, it is zero, which tells wxPython to leave the widget at its default proportion.

    The third argument is flag. You can actually pass in multiple flags if you wish as long as you separate them with a pipe character: |. The wxPython toolkit uses | to add flags using a series of bitwise ORs.

    In this example, you add the text control with the wx.ALL and wx.EXPAND flags. The wx.ALL flag tells wxPython that you want to add a border on all sides of the widget while wx.EXPAND makes the widgets expand as much as they can within the sizer.

    Finally, you have the border parameter, which tells wxPython how many pixels of border you want around the widget. The userData parameter is only used when you want to do something complex with your sizing of the widget and is actually quite rare to see in practice.

    Adding the button to the sizer follows the exact same steps. However, to make things a bit more interesting, I went ahead and switched out the wx.EXPAND flag for wx.CENTER so that the button would be centered on-screen.

    When you run this version of the code, your application should look like the following:

    Hello World in wxPython with Sizers

    If you’d like to learn more about sizers, the wxPython documentation has a nice page on the topic.

    Adding an Event

    While your application looks more interesting visually, it still doesn’t really do anything. For example, if you press the button, nothing really happens.

    Let’s give the button a job:

    import wx
    
    class MyFrame(wx.Frame):    
        def __init__(self):
            super().__init__(parent=None, title='Hello World')
            panel = wx.Panel(self)        
            my_sizer = wx.BoxSizer(wx.VERTICAL)        
            self.text_ctrl = wx.TextCtrl(panel)
            my_sizer.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)        
            my_btn = wx.Button(panel, label='Press Me')
            my_btn.Bind(wx.EVT_BUTTON, self.on_press)
            my_sizer.Add(my_btn, 0, wx.ALL | wx.CENTER, 5)        
            panel.SetSizer(my_sizer)        
            self.Show()
    
        def on_press(self, event):
            value = self.text_ctrl.GetValue()
            if not value:
                print("You didn't enter anything!")
            else:
                print(f'You typed: "{value}"')
    
    if __name__ == '__main__':
        app = wx.App()
        frame = MyFrame()
        app.MainLoop()
    

    The widgets in wxPython allow you to attach event bindings to them so that they can respond to certain types of events.

    Note: The code block above uses f-strings. You can read all about them in Python 3’s f-Strings: An Improved String Formatting Syntax (Guide).

    You want the button to do something when the user presses it. You can accomplish this by calling the button’s .Bind() method. .Bind() takes the event you want to bind to, the handler to call when the event happens, an optional source, and a couple of optional ids.

    In this example, you bind your button object to the wx.EVT_BUTTON event and tell it to call on_press() when that event gets fired.

    An event gets “fired” when the user does the event you have bound to. In this case, the event that you set up is the button press event, wx.EVT_BUTTON.

    .on_press() accepts a second argument that you can call event. This is by convention. You could call it something else if you wanted to. However, the event parameter here refers to the fact that when this method is called, its second argument should be an event object of some sort.

    Within .on_press(), you can get the text control’s contents by calling its GetValue() method. You then print a string to stdout depending on what the contents of the text control is.

    Now that you have the basics out of the way, let’s learn how to create an application that does something useful!

    Creating a Working Application

    The first step when creating something new is to figure out what you want to create. In this case, I have taken the liberty of making that decision for you. You will learn how to create a MP3 tag editor! The next step when creating something new is to find out what packages can help you accomplish your task.

    If you do a Google search for Python mp3 tagging, you will find you have several options:

    I tried out a couple of these and decided that eyeD3 had a nice API that you could use without getting bogged down with the MP3’s ID3 specification. You can install eyeD3 using pip, like this:

    $ pip install eyed3
    

    When installing this package on macOS, you may need to install libmagic using brew. Windows and Linux users shouldn’t have any issues installing eyeD3.

    Designing the User Interface

    When it comes to designing an interface, it’s always nice to just kind of sketch out how you think the user interface should look.

    You will need to be able to do the following:

    Most user interfaces use a menu or a button for opening files or folders. You can go with a File menu for this. Since you will probably want to see tags for multiple MP3 files, you will need to find a widget that can do this in a nice manner.

    Something that is tabular with columns and rows would be ideal because then you can have labeled columns for the MP3 tags. The wxPython toolkit has a few widgets that would work for this, with the top two being the following:

    You should use wx.ListCtrl in this case as the Grid widget is overkill, and frankly it is also quite a bit more complex. Finally, you need a button to use to edit a selected MP3’s tag.

    Now that you know what you want, you can draw it up:

    MP3 Editor in wxPython

    The illustration above gives us an idea of how the application should look. Now that you know what you want to do, it’s time to code!

    Creating the User Interface

    There are many different approaches when it comes to writing a new application. For example, do you need to follow the Model-View-Controller design pattern? How do you split up the classes? One class per file? There are many such questions, and as you get more experienced with GUI design, you’ll know how you want to answer them.

    In your case, you really only need two classes:

    You could argue for creating a controller type module as well, but for something like this, you really do not need it. A case could also be made for putting each class into its own module, but to keep it compact, you will create a single Python file for all of your code.

    Let’s start with imports and the panel class:

    import eyed3
    import glob
    import wx
    
    class Mp3Panel(wx.Panel):    
        def __init__(self, parent):
            super().__init__(parent)
            main_sizer = wx.BoxSizer(wx.VERTICAL)
            self.row_obj_dict = {}
    
            self.list_ctrl = wx.ListCtrl(
                self, size=(-1, 100), 
                style=wx.LC_REPORT | wx.BORDER_SUNKEN
            )
            self.list_ctrl.InsertColumn(0, 'Artist', width=140)
            self.list_ctrl.InsertColumn(1, 'Album', width=140)
            self.list_ctrl.InsertColumn(2, 'Title', width=200)
            main_sizer.Add(self.list_ctrl, 0, wx.ALL | wx.EXPAND, 5)        
            edit_button = wx.Button(self, label='Edit')
            edit_button.Bind(wx.EVT_BUTTON, self.on_edit)
            main_sizer.Add(edit_button, 0, wx.ALL | wx.CENTER, 5)        
            self.SetSizer(main_sizer)
    
        def on_edit(self, event):
            print('in on_edit')
    
        def update_mp3_listing(self, folder_path):
            print(folder_path)
    

    Here, you import the eyed3 package, Python’s glob package, and the wx package for your user interface. Next, you subclass wx.Panel and create your user interface. You need a dictionary for storing data about your MP3s, which you can name row_obj_dict.

    Then you create a wx.ListCtrl and set it to report mode (wx.LC_REPORT) with a sunken border (wx.BORDER_SUNKEN). The list control can take on a few other forms depending on the style flag that you pass in, but the report flag is the most popular.

    To make the ListCtrl have the correct headers, you will need to call .InsertColumn() for each column header. You then supply the index of the column, its label, and how wide in pixels the column should be.

    The last step is to add your Edit button, an event handler, and a method. You can create the binding to the event and leave the method that it calls empty for now.

    Now you should write the code for the frame:

    class Mp3Frame(wx.Frame):    
        def __init__(self):
            super().__init__(parent=None,
                             title='Mp3 Tag Editor')
            self.panel = Mp3Panel(self)
            self.Show()
    
    if __name__ == '__main__':
        app = wx.App(False)
        frame = Mp3Frame()
        app.MainLoop()
    

    This class is much simpler than the first one in that all you need to do is set the title of the frame and instantiate the panel class, Mp3Panel. When you are all done, your user interface should look like this:

    wxPython MP3 Tag Editor

    The user interface looks almost right, but you don’t have a File menu. This makes it impossible to add MP3s to the application and edit their tags!

    Let’s fix that now.

    Make a Functioning Application

    The first step in making your application work is to update the application so that it has a File menu because then you can add MP3 files to your creation. Menus are almost always added to the wx.Frame class, so that is the class you need to modify.

    Note: Some applications have moved away from having menus in their applications. One of the first to do so was Microsoft Office when they added the Ribbon Bar. The wxPython toolkit has a custom widget that you can use to create ribbons in wx.lib.agw.ribbon.

    The other type of application that has dropped menus of late are web browsers, such as Google Chrome and Mozilla Firefox. They just use toolbars nowadays.

    Let’s learn how to add a menu bar to our application:

    class Mp3Frame(wx.Frame):
    
        def __init__(self):
            wx.Frame.__init__(self, parent=None, 
                              title='Mp3 Tag Editor')
            self.panel = Mp3Panel(self)
            self.create_menu()
            self.Show()
    
        def create_menu(self):
            menu_bar = wx.MenuBar()
            file_menu = wx.Menu()
            open_folder_menu_item = file_menu.Append(
                wx.ID_ANY, 'Open Folder', 
                'Open a folder with MP3s'
            )
            menu_bar.Append(file_menu, '&File')
            self.Bind(
                event=wx.EVT_MENU, 
                handler=self.on_open_folder,
                source=open_folder_menu_item,
            )
            self.SetMenuBar(menu_bar)
    
        def on_open_folder(self, event):
            title = "Choose a directory:"
            dlg = wx.DirDialog(self, title, 
                               style=wx.DD_DEFAULT_STYLE)
            if dlg.ShowModal() == wx.ID_OK:
                self.panel.update_mp3_listing(dlg.GetPath())
            dlg.Destroy()
    

    Here, you add a call to .create_menu() within the class’s constructor. Then in .create_menu() itself, you will create a wx.MenuBar instance and a wx.Menu instance.

    To add a menu item to a menu, you call the menu instance’s .Append() and pass it the following:

    Next, you need to add the menu to the menubar, so you will need to call the menubar’s .Append(). It takes the menu instance and the label for menu. This label is a bit odd in that you called it &File instead of File. The ampersand tells wxPython to create a keyboard shortcut of Alt+F to open the File menu using just your keyboard.

    Note: If you would like to add keyboard shortcuts to your application, then you will want to use an instance of wx.AcceleratorTable to create them. You can read more about Accerator Tables in the wxPython documentation.

    To create an event binding, you will need to call self.Bind(), which binds the frame to wx.EVT_MENU. When you use self.Bind() for a menu event, you need to not only tell wxPython which handler to use, but also which source to bind the handler to.

    Finally, you must call the frame’s .SetMenuBar() and pass it the menubar instance for it to be shown to the user.

    Now that you have the menu added to your frame, let’s go over the menu item’s event handler, which is reproduced again below:

    def on_open_folder(self, event):
        title = "Choose a directory:"
        dlg = wx.DirDialog(self, title, style=wx.DD_DEFAULT_STYLE)
        if dlg.ShowModal() == wx.ID_OK:
            self.panel.update_mp3_listing(dlg.GetPath())
        dlg.Destroy()
    

    Since you want the user to choose a folder that contains MP3s, you will want to use wxPython’s wx.DirDialog. The wx.DirDialog allows the user to only open directories.

    You can set the dialog’s title and various style flags. To show the dialog, you will need to call .ShowModal(). This will cause the dialog to show modally, which means that the user won’t be able to interact with your main application while the dialog is shown.

    If the user presses the dialog’s OK button, you can get the user’s path choice via the dialog’s .GetPath(). You will want to pass that path to your panel class, which you can do here by calling the panel’s .update_mp3_listing().

    Finally you need to close the dialog. To close a dialog, the recommended method is to call its .Destroy().

    Dialogs do have a .Close() method, but that basically just hides the dialog, and it will not destroy itself when you close your application, which can lead to weird issues such as your application now shutting down properly. It’s simpler to call .Destroy() on the dialog to prevent this issue.

    Now let’s update your Mp3Panel class. You can start by updating .update_mp3_listing():

    def update_mp3_listing(self, folder_path):
        self.current_folder_path = folder_path
        self.list_ctrl.ClearAll()
    
        self.list_ctrl.InsertColumn(0, 'Artist', width=140)
        self.list_ctrl.InsertColumn(1, 'Album', width=140)
        self.list_ctrl.InsertColumn(2, 'Title', width=200)
        self.list_ctrl.InsertColumn(3, 'Year', width=200)
    
        mp3s = glob.glob(folder_path + '/*.mp3')
        mp3_objects = []
        index = 0
        for mp3 in mp3s:
            mp3_object = eyed3.load(mp3)
            self.list_ctrl.InsertItem(index, 
                mp3_object.tag.artist)
            self.list_ctrl.SetItem(index, 1, 
                mp3_object.tag.album)
            self.list_ctrl.SetItem(index, 2, 
                mp3_object.tag.title)
            mp3_objects.append(mp3_object)
            self.row_obj_dict[index] = mp3_object
            index += 1
    

    Here you set the current directory to the specified folder and then you clear the list control. This keeps the list control fresh and only showing the MP3s that you are currently working on. That also means that you need to re-insert all the columns again.

    Next, you’ll want to take the folder that was passed in and use Python’s glob module to search for MP3 files.

    Then you can loop over the MP3s and turn them into eyed3 objects. You can do this by calling the .load() of eyed3. Assuming that the MP3s have the appropriate tags already, you can then add the artist, album, and title of the MP3 to the list control.

    Interestingly, the method of adding a new row to a list control object is by calling .InsertItem() for the first column and SetItem() for all the subsequent columns.

    The last step is to save off your MP3 object to your Python dictionary, row_obj_dict.

    Now you need to update the .on_edit() event handler so that you can edit an MP3’s tags:

    def on_edit(self, event):
        selection = self.list_ctrl.GetFocusedItem()
        if selection >= 0:
            mp3 = self.row_obj_dict[selection]
            dlg = EditDialog(mp3)
            dlg.ShowModal()
            self.update_mp3_listing(self.current_folder_path)
            dlg.Destroy()
    

    The first thing you need to do is get the user’s selection by calling the list control’s .GetFocusedItem().

    If the user has not selected anything in the list control, it will return -1. Assuming that the user did select something, you will want to extract the MP3 object from your dictionary and open a MP3 tag editor dialog. This will be a custom dialog that you will use to edit the artist, album, and title tags of the MP3 file.

    As usual, show the dialog modally. When the dialog closes, the last two lines in .on_edit() will execute. These two lines will update the list control so it displays the current MP3 tag information that the user just edited and destroy the dialog.

    Creating an Editing Dialog

    The final piece of the puzzle is creating an MP3 tag editing dialog. For brevity, we will skip sketching out this interface as it is a series of rows that contains labels and text controls. The text controls should have the existing tag information pre-populated within them. You can create a label for the text controls by creating instances of wx.StaticText.

    When you need to create a custom dialog, the wx.Dialog class is your friend. You can use that to design the editor:

    class EditDialog(wx.Dialog):    
        def __init__(self, mp3):
            title = f'Editing "{mp3.tag.title}"'
            super().__init__(parent=None, title=title)        
            self.mp3 = mp3        
            self.main_sizer = wx.BoxSizer(wx.VERTICAL)        
            self.artist = wx.TextCtrl(
                self, value=self.mp3.tag.artist)
            self.add_widgets('Artist', self.artist)        
            self.album = wx.TextCtrl(
                self, value=self.mp3.tag.album)
            self.add_widgets('Album', self.album)        
            self.title = wx.TextCtrl(
                self, value=self.mp3.tag.title)
            self.add_widgets('Title', self.title)        
            btn_sizer = wx.BoxSizer()
            save_btn = wx.Button(self, label='Save')
            save_btn.Bind(wx.EVT_BUTTON, self.on_save)        
            btn_sizer.Add(save_btn, 0, wx.ALL, 5)
            btn_sizer.Add(wx.Button(
                self, id=wx.ID_CANCEL), 0, wx.ALL, 5)
            self.main_sizer.Add(btn_sizer, 0, wx.CENTER)        
            self.SetSizer(self.main_sizer)
    

    Here you want to start off by sub-classing wx.Dialog and giving it a custom title based on the title of the MP3 that you are editing.

    Next you can create the sizer you want to use and the widgets. To make things easier, you can create a helper method called .add_widgets() for adding the wx.StaticText widgets as rows with the text control instances. The only other widget here is the Save button.

    Let’s write the add_widgets method next:

        def add_widgets(self, label_text, text_ctrl):
            row_sizer = wx.BoxSizer(wx.HORIZONTAL)
            label = wx.StaticText(self, label=label_text,
                                  size=(50, -1))
            row_sizer.Add(label, 0, wx.ALL, 5)
            row_sizer.Add(text_ctrl, 1, wx.ALL | wx.EXPAND, 5)
            self.main_sizer.Add(row_sizer, 0, wx.EXPAND)
    

    add_widgets() takes the label’s text and the text control instance. It then creates a horizontally oriented BoxSizer.

    Next you will create an instance of wx.StaticText using the passed-in text for its label parameter. You will also set its size to be 50 pixels wide and the default height is set with a -1. Since you want the label before the text control, you will add the StaticText widget to your BoxSizer first and then add the text control .

    Finally, you want to add the horizontal sizer to the top level vertical sizer. By nesting the sizers in each other, you can design complex applications.

    Now you will need to create the on_save() event handler so that you can save your changes:

        def on_save(self, event):
            self.mp3.tag.artist = self.artist.GetValue()
            self.mp3.tag.album = self.album.GetValue()
            self.mp3.tag.title = self.title.GetValue()
            self.mp3.tag.save()
            self.Close()
    

    Here you set the tags to the contents of the text controls and then call the eyed3 object’s .save(). Finally, you call the .Close() of the dialog. The reason you call .Close() here instead of .Destroy() is that you already call .Destroy() in the .on_edit() of your panel subclass.

    Now your application is complete!

    Conclusion

    You learned a lot about wxPython in this article. You became familiar with the basics of creating GUI applications using wxPython.

    You now know more about the following:

    Finally you learned how to create a working application, an MP3 tag editor. You can use what you learned in this article to continue to enhance this application or perhaps create an amazing application on your own.

    The wxPython GUI toolkit is robust and full of interesting widgets that you can use to build cross-platform applications. You are limited by only your imagination.

    Further Reading

    If you would like to learn more about wxPython, you can check out some of the following links:

    For more information on what else you can do with Python, you might want to check out What Can I Do with Python? If you’d like to learn more about Python’s super(), then Supercharge Your Classes With Python super() may be just right for you.

    You can also download the code for the MP3 tag editor application that you created in this article if you want to study it more in depth.


    [ 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 ]

    March 18, 2019 02:00 PM UTC


    Podcast.__init__

    Wes McKinney's Career In Python For Data Analysis

    Python has become one of the dominant languages for data science and data analysis. Wes McKinney has been working for a decade to make tools that are easy and powerful, starting with the creation of Pandas, and eventually leading to his current work on Apache Arrow. In this episode he discusses his motivation for this work, what he sees as the current challenges to be overcome, and his hopes for the future of the industry.

    Summary

    Python has become one of the dominant languages for data science and data analysis. Wes McKinney has been working for a decade to make tools that are easy and powerful, starting with the creation of Pandas, and eventually leading to his current work on Apache Arrow. In this episode he discusses his motivation for this work, what he sees as the current challenges to be overcome, and his hopes for the future of the industry.

    Announcements

    • Hello and welcome to Podcast.__init__, the podcast about Python and the people who make it great.
    • 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 200 Gbit/s private networking, scalable shared block storage, node balancers, and a 40 Gbit/s public network, all controlled by a brand new API you’ve got everything you need to scale up. And for your tasks that need fast computation, such as training machine learning models, they just launched dedicated CPU instances. Go to pythonpodcast.com/linode to get a $20 credit and launch a new server in under a minute. And don’t forget to thank them for their continued support of this show!
    • Visit the site to subscribe to the show, sign up for the newsletter, and read the show notes. And if you have any questions, comments, or suggestions I would love to hear them. You can reach me on Twitter at @Podcast__init__ or email hosts@podcastinit.com)
    • 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
    • Check out the Practical AI podcast from our friends at Changelog Media to learn and stay up to date with what’s happening in AI
    • You listen to this show to learn and stay up to date with the ways that Python is being used, including the latest in machine learning and data analysis. For even more opportunities to meet, listen, and learn from your peers you don’t want to miss out on this year’s conference season. We have partnered with O’Reilly Media for the Strata conference in San Francisco on March 25th and the Artificial Intelligence conference in NYC on April 15th. Here in Boston, starting on May 17th, you still have time to grab a ticket to the Enterprise Data World, and from April 30th to May 3rd is the Open Data Science Conference. Go to pythonpodcast.com/conferences to learn more and take advantage of our partner discounts when you register.
    • Your host as usual is Tobias Macey and today I’m interviewing Wes McKinney about his contributions to the Python community and his current projects to make data analytics easier for everyone

    Interview

    • Introductions
    • How did you get introduced to Python?
    • You have spent a large portion of your career on building tools for data science and analytics in the Python ecosystem. What is your motivation for focusing on this problem domain?
    • Having been an open source author and contributor for many years now, what are your current thoughts on paths to sustainability?
    • What are some of the common challenges pertaining to data analysis that you have experienced in the various work environments and software projects that you have been involved in?
      • What area(s) of data science and analytics do you find are not receiving the attention that they deserve?
    • Recently there has been a lot of focus and excitement around the capabilities of neural networks and deep learning. In your experience, what are some of the shortcomings or blind spots to that class of approach that would be better served by other classes of solution?
    • Your most recent work is focused on the Arrow project for improving interoperability across languages. What are some of the cases where a Python developer would want to incorporate capabilities from other runtimes?
      • Do you think that we should be working to replicate some of those capabilities into the Python language and ecosystem, or is that wasted effort that would be better spent elsewhere?
    • Now that Pandas has been in active use for over a decade and you have had the opportunity to get some space from it, what are your thoughts on its success?
      • With the perspective that you have gained in that time, what would you do differently if you were starting over today?
    • You are best known for being the creator of Pandas, but can you list some of the other achievements that you are most proud of?
    • What projects are you most excited to be working on in the near to medium future?
    • What are your grand ambitions for the future of the data science community, both in and outside of the Python ecosystem?
    • Do you have any parting advice for active or aspiring data scientists, or resources that you would like to recommend?

    Keep In Touch

    Picks

    Links

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

    March 18, 2019 10:32 AM UTC