26 Jul 2017

feedPlanet Python

PyPy Development: Binary wheels for PyPy

Hi,

this is a short blog post, just to announce the existence of this Github repository, which contains binary PyPy wheels for some selected packages. The availability of binary wheels means that you can install the packages much more quickly, without having to wait for compilation.


At the moment of writing, these packages are available:


For now, we provide only wheels built on Ubuntu, compiled for PyPy 5.8.
In particular, it is worth noting that they are not manylinux1 wheels, which means they could not work on other Linux distributions. For more information, see the explanation in the README of the above repo.

Moreover, the existence of the wheels does not guarantee that they work correctly 100% of the time. they still depend on cpyext, our C-API emulation layer, which is still work-in-progress, although it has become better and better during the last months. Again, the wheels are there only to save compilation time.

To install a package from the wheel repository, you can invoke pip like this:

$ pip install --extra-index https://antocuni.github.io/pypy-wheels/ubuntu numpy


Happy installing!

26 Jul 2017 4:45pm GMT

PyPy Development: Binary wheels for PyPy

Hi,

this is a short blog post, just to announce the existence of this Github repository, which contains binary PyPy wheels for some selected packages. The availability of binary wheels means that you can install the packages much more quickly, without having to wait for compilation.


At the moment of writing, these packages are available:


For now, we provide only wheels built on Ubuntu, compiled for PyPy 5.8.
In particular, it is worth noting that they are not manylinux1 wheels, which means they could not work on other Linux distributions. For more information, see the explanation in the README of the above repo.

Moreover, the existence of the wheels does not guarantee that they work correctly 100% of the time. they still depend on cpyext, our C-API emulation layer, which is still work-in-progress, although it has become better and better during the last months. Again, the wheels are there only to save compilation time.

To install a package from the wheel repository, you can invoke pip like this:

$ pip install --extra-index https://antocuni.github.io/pypy-wheels/ubuntu numpy


Happy installing!

26 Jul 2017 4:45pm GMT

Tarek Ziade: Python Microservices Development

My new book, Python Microservices Development is out!

The last time I wrote a book, I was pretty sure I would not write a new one -- or at least not about Python. Writing a book is a lot of work.

The hard part is mostly about not quitting. After a day of work and taking care of the kids, sitting down again at my desk for a couple of hours was just hard, in particular since I do other stuff like running. I stole time from my wife.

The topic, "microservices" was also not easy to come around. When I was first approached by Packt to write it, I said no because I could not see any value of writing yet another book on that trendy (if not buzzwordy) topic.

But the project grew on me. I realized that in the past seven years, I have been working on services at Mozilla, we did move from a monolithic model to a microservices model. It happened because we moved most of our services to a cloud vendor, and when you do this, your application consumes a lot of services, and you end up splitting your applications into smaller pieces.

While picking Python 3 was a given, I hesitated a lot about writing the book using an asynchronous framework. I ended up sticking with a synchronous framework (Flask). Synchronous programming still seems to be mainstream in Python land. If we do a 2nd edition in a couple of years, I would probably use aiohttp :)

The other challenge is English. It is not my native language, and while I used Grammarly and I was helped a lot by Packt (they improved their editing process a lot since my first book there) it's probably something you will notice if you read it.

Technically speaking, I think I have done a good job at explaining how I think microservices should be developed. It should be useful for people that are wondering how to build their applications. Although I wished I had more time to finish polishing some of the code that goes with the book, thankfully that's on GitHub, so I still have a bit of time to finish that.

Kudos to Wil Khane-Green, my technical reviewer, who did a fantastic work. The book content is much better, thanks to him.

If you buy the book, let me know what you think, and do not hesitate to interact with me on Github or by email.

26 Jul 2017 4:22pm GMT

Tarek Ziade: Python Microservices Development

My new book, Python Microservices Development is out!

The last time I wrote a book, I was pretty sure I would not write a new one -- or at least not about Python. Writing a book is a lot of work.

The hard part is mostly about not quitting. After a day of work and taking care of the kids, sitting down again at my desk for a couple of hours was just hard, in particular since I do other stuff like running. I stole time from my wife.

The topic, "microservices" was also not easy to come around. When I was first approached by Packt to write it, I said no because I could not see any value of writing yet another book on that trendy (if not buzzwordy) topic.

But the project grew on me. I realized that in the past seven years, I have been working on services at Mozilla, we did move from a monolithic model to a microservices model. It happened because we moved most of our services to a cloud vendor, and when you do this, your application consumes a lot of services, and you end up splitting your applications into smaller pieces.

While picking Python 3 was a given, I hesitated a lot about writing the book using an asynchronous framework. I ended up sticking with a synchronous framework (Flask). Synchronous programming still seems to be mainstream in Python land. If we do a 2nd edition in a couple of years, I would probably use aiohttp :)

The other challenge is English. It is not my native language, and while I used Grammarly and I was helped a lot by Packt (they improved their editing process a lot since my first book there) it's probably something you will notice if you read it.

Technically speaking, I think I have done a good job at explaining how I think microservices should be developed. It should be useful for people that are wondering how to build their applications. Although I wished I had more time to finish polishing some of the code that goes with the book, thankfully that's on GitHub, so I still have a bit of time to finish that.

Kudos to Wil Khane-Green, my technical reviewer, who did a fantastic work. The book content is much better, thanks to him.

If you buy the book, let me know what you think, and do not hesitate to interact with me on Github or by email.

26 Jul 2017 4:22pm GMT

DataCamp: New Python Course: Data Types for Data Science

Hello Python users! New course launching today: Data Types for Data Science by Jason Myers!

Have you got your basic Python programming chops down for Data Science but are yearning for more? Then this is the course for you. Herein, you'll consolidate and practice your knowledge of lists, dictionaries, tuples, sets, and date times. You'll see their relevance in working with lots of real data and how to leverage several of them in concert to solve multistep problems, including an extended case study using Chicago metropolitan area transit data. You'll also learn how to use many of the objects in the Python Collections module, which will allow you to store and manipulate your data for a variety of Data Scientific purposes. After taking this course, you'll be ready to tackle many Data Science challenges Pythonically.

Take me to chapter 1!

Data Types for Data Science features interactive exercises that combine high-quality video, in-browser coding, and gamification for an engaging learning experience that will make you a master in data science with Python!


What you'll learn:

Chapter 1: Fundamental data types

This chapter will introduce you to the fundamental Python data types - lists, sets, and tuples. These data containers are critical as they provide the basis for storing and looping over ordered data. To make things interesting, you'll apply what you learn about these types to answer questions about the New York Baby Names dataset!

Chapter 2: Dictionaries - the root of Python

At the root of all things Python is a dictionary. Herein, you'll learn how to use them to safely handle data that can be viewed in a variety of ways to answer even more questions about the New York Baby Names dataset. You'll explore how to loop through data in a dictionary, access nested data, add new data, and come to appreciate all of the wonderful capabilities of Python dictionaries.

Chapter 3: Meet the collections module

The collections module is part of Python's standard library and holds some more advanced data containers. You'll learn how to use the Counter, defaultdict, OrderedDict and namedtuple in the context of answering questions about the Chicago transit dataset.

Chapter 4: Handling Dates and Times

Handling times can seem daunting at times, but here, you'll dig in and learn how to create datetime objects, print them, look to the past and to the future. Additionally, you'll learn about some third party modules that can make all of this easier. You'll continue to use the Chicago Transit dataset to answer questions about transit times.

Chapter 5: Answering Data Science Questions

Finally, time for a case study to reinforce all of your learning so far! You'll use all the containers and data types you've learned about to answer several real world questions about a dataset containing information about crime in Chicago.

Learn all there is to know about Data Types for Data Science today!

26 Jul 2017 2:32pm GMT

DataCamp: New Python Course: Data Types for Data Science

Hello Python users! New course launching today: Data Types for Data Science by Jason Myers!

Have you got your basic Python programming chops down for Data Science but are yearning for more? Then this is the course for you. Herein, you'll consolidate and practice your knowledge of lists, dictionaries, tuples, sets, and date times. You'll see their relevance in working with lots of real data and how to leverage several of them in concert to solve multistep problems, including an extended case study using Chicago metropolitan area transit data. You'll also learn how to use many of the objects in the Python Collections module, which will allow you to store and manipulate your data for a variety of Data Scientific purposes. After taking this course, you'll be ready to tackle many Data Science challenges Pythonically.

Take me to chapter 1!

Data Types for Data Science features interactive exercises that combine high-quality video, in-browser coding, and gamification for an engaging learning experience that will make you a master in data science with Python!


What you'll learn:

Chapter 1: Fundamental data types

This chapter will introduce you to the fundamental Python data types - lists, sets, and tuples. These data containers are critical as they provide the basis for storing and looping over ordered data. To make things interesting, you'll apply what you learn about these types to answer questions about the New York Baby Names dataset!

Chapter 2: Dictionaries - the root of Python

At the root of all things Python is a dictionary. Herein, you'll learn how to use them to safely handle data that can be viewed in a variety of ways to answer even more questions about the New York Baby Names dataset. You'll explore how to loop through data in a dictionary, access nested data, add new data, and come to appreciate all of the wonderful capabilities of Python dictionaries.

Chapter 3: Meet the collections module

The collections module is part of Python's standard library and holds some more advanced data containers. You'll learn how to use the Counter, defaultdict, OrderedDict and namedtuple in the context of answering questions about the Chicago transit dataset.

Chapter 4: Handling Dates and Times

Handling times can seem daunting at times, but here, you'll dig in and learn how to create datetime objects, print them, look to the past and to the future. Additionally, you'll learn about some third party modules that can make all of this easier. You'll continue to use the Chicago Transit dataset to answer questions about transit times.

Chapter 5: Answering Data Science Questions

Finally, time for a case study to reinforce all of your learning so far! You'll use all the containers and data types you've learned about to answer several real world questions about a dataset containing information about crime in Chicago.

Learn all there is to know about Data Types for Data Science today!

26 Jul 2017 2:32pm GMT

The Three of Wands: attrs I: The Basics

This is the first article in my series on the inner workings of attrs.

Attrs is a Python library for defining classes a different (much better) way. The docs can be found at attrs.readthedocs.org and are pretty good; they explain how and why you should use attrs. And as a Python developer in 2017 you should be using attrs.

This attrs series is about how attrs works under the hood, so go read the docs and use it somewhere first. It'll make following along much easier. The source code is available on GitHub; at this time it's not a particularly large codebase at around 900 lines of non-test code. (Django, as an example, currently has around 76000 lines of Python.)

Here's the simplest useful class the attrs way:

@attr.s
class C:  
    a = attr.ib()

(I'm omitting boilerplate like imports and using Python 3.6+.)

This will get you a class with a single attribute and the most common boilerplate (__init__, __repr__, ...) generated and ready to be used. But what's actually happening here?

Let's take a look at this class without the attr.s decorator applied. (Leaving it out is an error and won't get you a working class, we're doing it now to take a look under the hood.)

class C:  
    a = attr.ib()

So this is just a class with a single class (i.e. not instance) attribute, assigned the value of whatever the attr.ib() function returns. attr.ib is just a reference to the attr._make.attr function, which is a fairly thin wrapper around the attr._make._CountingAttr class.

This is a private class (as the leading underscore suggests) that holds the intermediate attribute state until the attr.s class decorator comes along and does something with it.

>>> C.a
_CountingAttr(counter=8, _default=NOTHING, repr=True, cmp=True, hash=None, init=True, metadata={})  

The counter is a global variable that gets incremented and assigned to _CountingAttr instances when they're created. It's there so you can count on the consistent ordering of attributes:

@attr.s
class D:  
    a = attr.ib()
    b = attr.ib()
    c = attr.ib()
    d = attr.ib()

>>> [a.name for a in attr.fields(D)]
['a', 'b', 'c', 'd']  # Note the ordering.

Attrs has relatively recently added a new way of defining attribute defaults:

@attr.s
class E:  
    a = attr.ib()

    @a.default
    def a_default(self):
        return 1

As you might guess by now, default is just a _CountingAttr method that updates its internal state. (It's also the reason the field on CountingAttr instances is called _default and not default.)

attr.s is a class decorator that gathers up these _CountingAttrs and converts them into attr.Attributes, which are public and immutable, before generating all the other methods. The Attributes get put into a tuple at C.__attrs_attrs__, and this tuple is what you get when you call attr.fields(C). If you want to inspect an attribute, fetch it using attr.fields(C).a and not C.a. C.a is deprecated and scheduled to be removed soon, and doesn't work on slot classes anyway.

Now, armed with this knowledge, you can customize your attributes before they get transformed and the other boilerplate methods get generated.

You'll also need some courage, since _CountingAttrs are a private implementation detail and might work differently in the next release of attrs. Attributes are safe to use and follow the usual deprecation period; ideally you should apply your customizations after the application of attr.s. I've chosen an example that's much easier to implement before attr.s.

As an exercise, let's code up a class decorator that will set all your attribute defaults to None if no other default was set (no default set is indicated by the _default field having the sentinel value attr.NOTHING). We just need to iterate over all _CountingAttrs and change their _default fields.

from attr import NOTHING  
from attr._make import _CountingAttr

def add_defaults(cl):  
    for obj in cl.__dict__.values():
        if not isinstance(obj, _CountingAttr) or obj._default is not NOTHING:
            continue
        obj._default = None
    return cl

Example usage:

@attr.s
@add_defaults
class C:  
    a = attr.ib(default=5)
    b = attr.ib()

>>> C()
C(a=5, b=None)  

26 Jul 2017 12:41pm GMT

The Three of Wands: attrs I: The Basics

This is the first article in my series on the inner workings of attrs.

Attrs is a Python library for defining classes a different (much better) way. The docs can be found at attrs.readthedocs.org and are pretty good; they explain how and why you should use attrs. And as a Python developer in 2017 you should be using attrs.

This attrs series is about how attrs works under the hood, so go read the docs and use it somewhere first. It'll make following along much easier. The source code is available on GitHub; at this time it's not a particularly large codebase at around 900 lines of non-test code. (Django, as an example, currently has around 76000 lines of Python.)

Here's the simplest useful class the attrs way:

@attr.s
class C:  
    a = attr.ib()

(I'm omitting boilerplate like imports and using Python 3.6+.)

This will get you a class with a single attribute and the most common boilerplate (__init__, __repr__, ...) generated and ready to be used. But what's actually happening here?

Let's take a look at this class without the attr.s decorator applied. (Leaving it out is an error and won't get you a working class, we're doing it now to take a look under the hood.)

class C:  
    a = attr.ib()

So this is just a class with a single class (i.e. not instance) attribute, assigned the value of whatever the attr.ib() function returns. attr.ib is just a reference to the attr._make.attr function, which is a fairly thin wrapper around the attr._make._CountingAttr class.

This is a private class (as the leading underscore suggests) that holds the intermediate attribute state until the attr.s class decorator comes along and does something with it.

>>> C.a
_CountingAttr(counter=8, _default=NOTHING, repr=True, cmp=True, hash=None, init=True, metadata={})  

The counter is a global variable that gets incremented and assigned to _CountingAttr instances when they're created. It's there so you can count on the consistent ordering of attributes:

@attr.s
class D:  
    a = attr.ib()
    b = attr.ib()
    c = attr.ib()
    d = attr.ib()

>>> [a.name for a in attr.fields(D)]
['a', 'b', 'c', 'd']  # Note the ordering.

Attrs has relatively recently added a new way of defining attribute defaults:

@attr.s
class E:  
    a = attr.ib()

    @a.default
    def a_default(self):
        return 1

As you might guess by now, default is just a _CountingAttr method that updates its internal state. (It's also the reason the field on CountingAttr instances is called _default and not default.)

attr.s is a class decorator that gathers up these _CountingAttrs and converts them into attr.Attributes, which are public and immutable, before generating all the other methods. The Attributes get put into a tuple at C.__attrs_attrs__, and this tuple is what you get when you call attr.fields(C). If you want to inspect an attribute, fetch it using attr.fields(C).a and not C.a. C.a is deprecated and scheduled to be removed soon, and doesn't work on slot classes anyway.

Now, armed with this knowledge, you can customize your attributes before they get transformed and the other boilerplate methods get generated.

You'll also need some courage, since _CountingAttrs are a private implementation detail and might work differently in the next release of attrs. Attributes are safe to use and follow the usual deprecation period; ideally you should apply your customizations after the application of attr.s. I've chosen an example that's much easier to implement before attr.s.

As an exercise, let's code up a class decorator that will set all your attribute defaults to None if no other default was set (no default set is indicated by the _default field having the sentinel value attr.NOTHING). We just need to iterate over all _CountingAttrs and change their _default fields.

from attr import NOTHING  
from attr._make import _CountingAttr

def add_defaults(cl):  
    for obj in cl.__dict__.values():
        if not isinstance(obj, _CountingAttr) or obj._default is not NOTHING:
            continue
        obj._default = None
    return cl

Example usage:

@attr.s
@add_defaults
class C:  
    a = attr.ib(default=5)
    b = attr.ib()

>>> C()
C(a=5, b=None)  

26 Jul 2017 12:41pm GMT

Catalin George Festila: The gtts python module.

This python module named gtts will create an mp3 file from spoken text via the Google TTS (Text-to-Speech) API.
The installation of the gtts python module under Windows 10.

C:\Python27\Scripts>pip install gtts
Collecting gtts
Downloading gTTS-1.2.0.tar.gz
Requirement already satisfied: six in c:\python27\lib\site-packages (from gtts)
Requirement already satisfied: requests in c:\python27\lib\site-packages (from gtts)
Collecting gtts_token (from gtts)
Downloading gTTS-token-1.1.1.zip
Requirement already satisfied: chardet3 .1.0="">=3.0.2 in c:\python27\lib\site-packages (from requests->gtts)
Requirement already satisfied: certifi>=2017.4.17 in c:\python27\lib\site-packages (from requests->gtts)
Requirement already satisfied: idna2 .6="">=2.5 in c:\python27\lib\site-packages (from requests->gtts)
Collecting urllib31 .22="">=1.21.1 (from requests->gtts)
Using cached urllib3-1.21.1-py2.py3-none-any.whl
Installing collected packages: gtts-token, gtts, urllib3
Running setup.py install for gtts-token ... done
Running setup.py install for gtts ... done
Found existing installation: urllib3 1.22
Uninstalling urllib3-1.22:
Successfully uninstalled urllib3-1.22
Successfully installed gtts-1.2.0 gtts-token-1.1.1 urllib3-1.21.1

Let's see a basic example:

from gtts import gTTS
import os
import pygame.mixer
from time import sleep

user_text=input("Type your text: ")

translate=gTTS(text=user_text ,lang='en')
translate.save('output.wav')

pygame.mixer.init()
path_name=os.path.realpath('output.wav')
real_path=path_name.replace('\\','\\\\')
pygame.mixer.music.load(open(real_path,"rb"))
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
sleep(1)

The text will be take by input into user_text variable.
You need to type the text into quotes also you will got a error.
The result will be one audio file named output.wav and play it by pygame python module.
This use the default voices for all languages. I don't find a way to change this voices with python.

26 Jul 2017 11:34am GMT

Catalin George Festila: The gtts python module.

This python module named gtts will create an mp3 file from spoken text via the Google TTS (Text-to-Speech) API.
The installation of the gtts python module under Windows 10.

C:\Python27\Scripts>pip install gtts
Collecting gtts
Downloading gTTS-1.2.0.tar.gz
Requirement already satisfied: six in c:\python27\lib\site-packages (from gtts)
Requirement already satisfied: requests in c:\python27\lib\site-packages (from gtts)
Collecting gtts_token (from gtts)
Downloading gTTS-token-1.1.1.zip
Requirement already satisfied: chardet3 .1.0="">=3.0.2 in c:\python27\lib\site-packages (from requests->gtts)
Requirement already satisfied: certifi>=2017.4.17 in c:\python27\lib\site-packages (from requests->gtts)
Requirement already satisfied: idna2 .6="">=2.5 in c:\python27\lib\site-packages (from requests->gtts)
Collecting urllib31 .22="">=1.21.1 (from requests->gtts)
Using cached urllib3-1.21.1-py2.py3-none-any.whl
Installing collected packages: gtts-token, gtts, urllib3
Running setup.py install for gtts-token ... done
Running setup.py install for gtts ... done
Found existing installation: urllib3 1.22
Uninstalling urllib3-1.22:
Successfully uninstalled urllib3-1.22
Successfully installed gtts-1.2.0 gtts-token-1.1.1 urllib3-1.21.1

Let's see a basic example:

from gtts import gTTS
import os
import pygame.mixer
from time import sleep

user_text=input("Type your text: ")

translate=gTTS(text=user_text ,lang='en')
translate.save('output.wav')

pygame.mixer.init()
path_name=os.path.realpath('output.wav')
real_path=path_name.replace('\\','\\\\')
pygame.mixer.music.load(open(real_path,"rb"))
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
sleep(1)

The text will be take by input into user_text variable.
You need to type the text into quotes also you will got a error.
The result will be one audio file named output.wav and play it by pygame python module.
This use the default voices for all languages. I don't find a way to change this voices with python.

26 Jul 2017 11:34am GMT

PyCharm: PyCharm 2017.2 Out Now: Docker Compose on Windows, SSH Agent and more

PyCharm 2017.2 is out now! Get it today for Docker Compose support on Windows, SSH Agent, Azure Databases, and Amazon Redshift support.


Get it from our website

Get PyCharm 2017.2 now from our website!

Please let us know what you think about PyCharm! You can reach us on Twitter, Facebook, and by leaving a comment on the blog.

PyCharm Team
-The Drive to Develop

26 Jul 2017 10:11am GMT

PyCharm: PyCharm 2017.2 Out Now: Docker Compose on Windows, SSH Agent and more

PyCharm 2017.2 is out now! Get it today for Docker Compose support on Windows, SSH Agent, Azure Databases, and Amazon Redshift support.


Get it from our website

Get PyCharm 2017.2 now from our website!

Please let us know what you think about PyCharm! You can reach us on Twitter, Facebook, and by leaving a comment on the blog.

PyCharm Team
-The Drive to Develop

26 Jul 2017 10:11am GMT

25 Jul 2017

feedPlanet Python

Stefan Behnel: What's new in Cython 0.26?

Cython 0.26 has finally been released and it comes with some big and several smaller new features, contributed by quite a number of non-core developers.

Probably the biggest addition, definitely codewise, is support for Pythran as a backend for NumPy array expressions, contributed by Adrien Guinet. Pythran understands many usage patterns for NumPy, including array expressions and some methods, and can directly be used from within Cython to compile NumPy using code by setting the directive np_pythran=True. Thus, if Pythran is available at compile time, users can avoid writing manual loops and instead often just use NumPy in the same way as they would from Python. Note that this does not currently work generically with Cython's memoryviews, so you need to declare the specific numpy.ndarray[] types in order to benefit from the translation. Also, this requires the C++ mode in Cython as Pythran generates C++ code.

The other major new feature in this release, and likely with an even wider impact, is pickling support for cdef classes (a.k.a. extension types). This is enabled by default for all classes with Python compatible attribute types, which explicitly excludes pointers and unions. Classes with struct type attributes are also excluded for practical reasons (such as a high code overhead), but can be enabled to support pickling with the class decorator @cython.auto_pickle(True). This was a long-standing feature for which users previously had to implement the pickle protocol themselves. Since Cython has all information about the extension type and its attributes, however, there was no technical reason why it can't also generate the support for pickling them, and it now does.

As always, there are several new optimisations including speed-ups for abs(complex), comparing strings and dispatching to specialised function implementations based on fused types arguments. Particularly interesting might be the faster GIL re-entry with the directive fast_gil=True. It tries to remember the current GIL lock state in the fast thread local storage and avoids costly calls into the thread and GIL handling APIs if possible, even when calling across multiple Cython modules.

A slightly controversial change now hides the C code lines from tracebacks by default. Cython exceptions used to show the failing line number of the generated C code in addition to the Cython module code line, now only the latter is shown, like in Python code. On the one hand, this removes clutter that is irrelevant for most users. On the other hand, it hides information that could help developers debug failures from bug reports. For debugging purposes, the re-inclusion of C code lines can now be enabled with a runtime setting as follows:

import cython_runtime
cython_runtime.cline_in_traceback=True

25 Jul 2017 2:33pm GMT

Stefan Behnel: What's new in Cython 0.26?

Cython 0.26 has finally been released and it comes with some big and several smaller new features, contributed by quite a number of non-core developers.

Probably the biggest addition, definitely codewise, is support for Pythran as a backend for NumPy array expressions, contributed by Adrien Guinet. Pythran understands many usage patterns for NumPy, including array expressions and some methods, and can directly be used from within Cython to compile NumPy using code by setting the directive np_pythran=True. Thus, if Pythran is available at compile time, users can avoid writing manual loops and instead often just use NumPy in the same way as they would from Python. Note that this does not currently work generically with Cython's memoryviews, so you need to declare the specific numpy.ndarray[] types in order to benefit from the translation. Also, this requires the C++ mode in Cython as Pythran generates C++ code.

The other major new feature in this release, and likely with an even wider impact, is pickling support for cdef classes (a.k.a. extension types). This is enabled by default for all classes with Python compatible attribute types, which explicitly excludes pointers and unions. Classes with struct type attributes are also excluded for practical reasons (such as a high code overhead), but can be enabled to support pickling with the class decorator @cython.auto_pickle(True). This was a long-standing feature for which users previously had to implement the pickle protocol themselves. Since Cython has all information about the extension type and its attributes, however, there was no technical reason why it can't also generate the support for pickling them, and it now does.

As always, there are several new optimisations including speed-ups for abs(complex), comparing strings and dispatching to specialised function implementations based on fused types arguments. Particularly interesting might be the faster GIL re-entry with the directive fast_gil=True. It tries to remember the current GIL lock state in the fast thread local storage and avoids costly calls into the thread and GIL handling APIs if possible, even when calling across multiple Cython modules.

A slightly controversial change now hides the C code lines from tracebacks by default. Cython exceptions used to show the failing line number of the generated C code in addition to the Cython module code line, now only the latter is shown, like in Python code. On the one hand, this removes clutter that is irrelevant for most users. On the other hand, it hides information that could help developers debug failures from bug reports. For debugging purposes, the re-inclusion of C code lines can now be enabled with a runtime setting as follows:

import cython_runtime
cython_runtime.cline_in_traceback=True

25 Jul 2017 2:33pm GMT

Stefan Behnel: What's new in Cython 0.25?

Cython 0.25 has been released in October 2016, so here's a quick writeup of the most relevant new features in this release.

My personal favourites are the call optimisations. Victor Stinner has done a great job throughout the year to optimise and benchmark different parts of CPython, and one of the things he came up with was a faster way to process function calls internally. For this, he added a new calling convention, METH_FASTCALL, which avoids tuple creation by passing positional arguments as a C array. I've added support for this to Cython and also ported a part of the CPython implementation to speed up calls to Python functions and PyCFunction functions from Cython code.

Further optimisations speed up f-string formatting, cython.inline() and some Python long integer operations (now also in Py2.7 and not only Py3).

The next big feature, one that has been on our list essentially forever, was finally added in 0.25. If you declare a special attribute __dict__ on a cdef class (a.k.a. extension type), if will have an instance dict that allows setting arbitrary attributes on the objects. Otherwise, extension types are limited to the declared attributes and trying to access undeclared ones would result in an AttributeError.

The C++ integration has received several minor improvements, including support for calling subclass methods from C++ classes implemented in Cython code, iterating over std::string with Cython's for-loop, typedef members in class declarations, or the typeid operator.

And a final little goodie is redundant declarations for pi and e in libc.math, which makes from libc cimport math pretty much a drop-in replacement for Python's import math.

25 Jul 2017 2:33pm GMT

Stefan Behnel: What's new in Cython 0.25?

Cython 0.25 has been released in October 2016, so here's a quick writeup of the most relevant new features in this release.

My personal favourites are the call optimisations. Victor Stinner has done a great job throughout the year to optimise and benchmark different parts of CPython, and one of the things he came up with was a faster way to process function calls internally. For this, he added a new calling convention, METH_FASTCALL, which avoids tuple creation by passing positional arguments as a C array. I've added support for this to Cython and also ported a part of the CPython implementation to speed up calls to Python functions and PyCFunction functions from Cython code.

Further optimisations speed up f-string formatting, cython.inline() and some Python long integer operations (now also in Py2.7 and not only Py3).

The next big feature, one that has been on our list essentially forever, was finally added in 0.25. If you declare a special attribute __dict__ on a cdef class (a.k.a. extension type), if will have an instance dict that allows setting arbitrary attributes on the objects. Otherwise, extension types are limited to the declared attributes and trying to access undeclared ones would result in an AttributeError.

The C++ integration has received several minor improvements, including support for calling subclass methods from C++ classes implemented in Cython code, iterating over std::string with Cython's for-loop, typedef members in class declarations, or the typeid operator.

And a final little goodie is redundant declarations for pi and e in libc.math, which makes from libc cimport math pretty much a drop-in replacement for Python's import math.

25 Jul 2017 2:33pm GMT

PyCharm: Interview: Paul Craven on Python Gaming and Teaching

Writing games in Python is fun, so how about using it to teach computer programming? Paul Craven is both a professor and the creator of Arcade, a 2d game library for Python. He's doing a webinar with us next week, so we talked to him about teaching Python, using Python 3 type hints, why another Python game library, and how IDEs fit into teaching.

paul_craven_splash

Thanks a bunch for doing the webinar next week. First, can you tell us a little bit about yourself?

I worked in the IT industry for 15 years before switching to teaching at Simpson College, a small 4-year college in Iowa. My main interest has been getting first-time programmers to realize that programming can be fun. That moment when a student cheers out loud because they finally figured out how to get sprites to move correctly on the screen? It is a beautiful thing to see.

You teach programming, and you created the Arcade game library to help. Before talking about Arcade, can you explain the motivation behind having a framework that you can teach?

Teaching is like engineering. Each semester you work to improve how you teach students. I had been using the Pygame library. But I wanted a library that I could improve on based on what I saw from students. For example:

Function and parameter names that students intuitively understand. Each year I had to teach them "set_mode" opens a window. Why not just have the function called "open_window"?
Support for functions students which ask for. In Pygame drawing ellipses with thick borders always had a moire pattern because of a bug in the library. And you can't tilt ellipses when you draw them. Every year I have a student that wants to draw a football. And each year they were frustrated that it looked awful. I wanted a library where it just worked.
Students would download a graphic for their sprite. But it would be too large and there was no easy way to scale the image. That always resulted in hours of wasted time explaining how to do the scaling. What if the library just supported scaling?

After a while I collected such a long list of things like that, I decided to create a game library that where I wouldn't have to teach "around" these issues.

Beyond using it for teaching, can you talk a bit about Arcade? What is it, how is it different, who might want to use it?

Arcade is great for sprite-based 2D games. It is simple and easy to get started with the library. There is no need to learn a complex framework. If you've wanted to create a game for fun, but Kivy, Unity, Unreal would just take more time to learn than what you've got, Arcade is a better choice. If you want to quickly create a scientific visualization without a lot of overhead code, Arcade can help you there too.

Arcade uses OpenGL and Pyglet. With OpenGL acceleration, it can draw a lot of sprites fast.

I use Arcade for my PyCharm tutorials and Arcade's Python 3.6 type hinting is a big reason. Can you talk about your experience, as a library author and teacher, with type hinting?

New programmers often get confused when calling functions and methods. What data does it expect? And when the program doesn't run, the students aren't yet experts in reading stack traces. So they are stuck with a 500 line program that doesn't work and they don't know why. Frustrating.

Type hinting can sometimes tell students that they are passing unexpected data to the function. It does this before they run the program. Before they've even moved to writing the next line of code. It seems trivial, but it's not. I found students able to create better, more complex programs because PyCharm and type hinting kept them from that error and allowed them to move on.

You also use PyCharm CE with your students. What's been your experience having beginners start with an IDE?

I've taught students with an IDE and without an IDE. The biggest advantage is how the IDE can help students catch errors early. PyCharm's built-in PEP-8 checking is huge. Also, built in spell-checking! Imagine trying to read program comments written without a spell-checker from today's student. Students come up with some interesting ways to spell words.

25 Jul 2017 9:38am GMT

PyCharm: Interview: Paul Craven on Python Gaming and Teaching

Writing games in Python is fun, so how about using it to teach computer programming? Paul Craven is both a professor and the creator of Arcade, a 2d game library for Python. He's doing a webinar with us next week, so we talked to him about teaching Python, using Python 3 type hints, why another Python game library, and how IDEs fit into teaching.

paul_craven_splash

Thanks a bunch for doing the webinar next week. First, can you tell us a little bit about yourself?

I worked in the IT industry for 15 years before switching to teaching at Simpson College, a small 4-year college in Iowa. My main interest has been getting first-time programmers to realize that programming can be fun. That moment when a student cheers out loud because they finally figured out how to get sprites to move correctly on the screen? It is a beautiful thing to see.

You teach programming, and you created the Arcade game library to help. Before talking about Arcade, can you explain the motivation behind having a framework that you can teach?

Teaching is like engineering. Each semester you work to improve how you teach students. I had been using the Pygame library. But I wanted a library that I could improve on based on what I saw from students. For example:

Function and parameter names that students intuitively understand. Each year I had to teach them "set_mode" opens a window. Why not just have the function called "open_window"?
Support for functions students which ask for. In Pygame drawing ellipses with thick borders always had a moire pattern because of a bug in the library. And you can't tilt ellipses when you draw them. Every year I have a student that wants to draw a football. And each year they were frustrated that it looked awful. I wanted a library where it just worked.
Students would download a graphic for their sprite. But it would be too large and there was no easy way to scale the image. That always resulted in hours of wasted time explaining how to do the scaling. What if the library just supported scaling?

After a while I collected such a long list of things like that, I decided to create a game library that where I wouldn't have to teach "around" these issues.

Beyond using it for teaching, can you talk a bit about Arcade? What is it, how is it different, who might want to use it?

Arcade is great for sprite-based 2D games. It is simple and easy to get started with the library. There is no need to learn a complex framework. If you've wanted to create a game for fun, but Kivy, Unity, Unreal would just take more time to learn than what you've got, Arcade is a better choice. If you want to quickly create a scientific visualization without a lot of overhead code, Arcade can help you there too.

Arcade uses OpenGL and Pyglet. With OpenGL acceleration, it can draw a lot of sprites fast.

I use Arcade for my PyCharm tutorials and Arcade's Python 3.6 type hinting is a big reason. Can you talk about your experience, as a library author and teacher, with type hinting?

New programmers often get confused when calling functions and methods. What data does it expect? And when the program doesn't run, the students aren't yet experts in reading stack traces. So they are stuck with a 500 line program that doesn't work and they don't know why. Frustrating.

Type hinting can sometimes tell students that they are passing unexpected data to the function. It does this before they run the program. Before they've even moved to writing the next line of code. It seems trivial, but it's not. I found students able to create better, more complex programs because PyCharm and type hinting kept them from that error and allowed them to move on.

You also use PyCharm CE with your students. What's been your experience having beginners start with an IDE?

I've taught students with an IDE and without an IDE. The biggest advantage is how the IDE can help students catch errors early. PyCharm's built-in PEP-8 checking is huge. Also, built in spell-checking! Imagine trying to read program comments written without a spell-checker from today's student. Students come up with some interesting ways to spell words.

25 Jul 2017 9:38am GMT

Python Insider: Python 3.5.4rc1 and Python 3.4.7rc1 are now available

Python 3.5.4rc1 and Python 3.4.7rc1 are now available for download.

You can download Python 3.5.4rc1 here, and you can download Python 3.4.7rc1 here.

25 Jul 2017 4:40am GMT

Python Insider: Python 3.5.4rc1 and Python 3.4.7rc1 are now available

Python 3.5.4rc1 and Python 3.4.7rc1 are now available for download.

You can download Python 3.5.4rc1 here, and you can download Python 3.4.7rc1 here.

25 Jul 2017 4:40am GMT

Peter Bengtsson: Find static files defined in django-pipeline but not found

If you're reading this you're probably familiar with how, in django-pipeline, you define bundles of static files to be combined and served. If you're not familiar with django-pipeline it's unlike this'll be of much help.

The Challenge (aka. the pitfall)

So you specify bundles by creating things in your settings.py something like this:

PIPELINE = {
    'STYLESHEETS': {
        'colors': {
            'source_filenames': (
              'css/core.css',
              'css/colors/*.css',
              'css/layers.css'
            ),
            'output_filename': 'css/colors.css',
            'extra_context': {
                'media': 'screen,projection',
            },
        },
    },
    'JAVASCRIPT': {
        'stats': {
            'source_filenames': (
              'js/jquery.js',
              'js/d3.js',
              'js/collections/*.js',
              'js/aplication.js',
            ),
            'output_filename': 'js/stats.js',
        }
    }
}

You do a bit more configuration and now, when you run ./manage.py collectstatic --noinput Django and django-pipeline will gather up all static files from all Django apps installed, then start post processing then and doing things like concatenating them into one file and doing stuff like minification etc.

The problem is, if you look at the example snippet above, there's a typo. Instead of js/application.js it's accidentally js/aplication.js. Oh noes!!

What's sad is it that nobody will notice (running ./manage.py collectstatic will exit with a 0). At least not unless you do some careful manual reviewing. Perhaps you will notice later, when you've pushed the site to prod, that the output file js/stats.js actually doesn't contain the code from js/application.js.

Or, you can automate it!

A Solution (aka. the hack)

I started this work this morning because the error actually happened to us. Thankfully not in production but our staging server produced a rendered HTML page with <link href="/static/css/report.min.cd784b4a5e2d.css" rel="stylesheet" type="text/css" /> which was an actual file but it was 0 bytes.

It wasn't that hard to figure out what the problem was because of the context of recent changes but it would have been nice to catch this during continuous integration.

So what we did was add an extra class to settings.STATICFILES_FINDERS called myproject.base.finders.LeftoverPipelineFinder. So now it looks like this:

# in settings.py

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'pipeline.finders.PipelineFinder',
    'myproject.finders.LeftoverPipelineFinder',  # the new hotness!
)

And here's the class implementation:

from pipeline.finders import PipelineFinder

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured


class LeftoverPipelineFinder(PipelineFinder):
    """This finder is expected to come AFTER 
    django.contrib.staticfiles.finders.FileSystemFinder and 
    django.contrib.staticfiles.finders.AppDirectoriesFinder in 
    settings.STATICFILES_FINDERS.
    If a path is looked for here it means it's trying to find a file
    that none of the regular staticfiles finders couldn't find.
    """
    def find(self, path, all=False):
        # Before we raise an error, try to find out where,
        # in the bundles, this was defined. This will make it easier to correct
        # the mistake.
        for config_name in 'STYLESHEETS', 'JAVASCRIPT':
            config = settings.PIPELINE[config_name]
            for key in config:
                if path in config[key]['source_filenames']:
                    raise ImproperlyConfigured(
                        'Static file {!r} can not be found anywhere. Defined in '
                        "PIPELINE[{!r}][{!r}]['source_filenames']".format(
                            path,
                            config_name,
                            key,
                        )
                    )
        # If the file can't be found AND it's not in bundles, there's
        # got to be something else really wrong.
        raise NotImplementedError(path)

Now, if you have a typo or something in your bundles, you'll get a nice error about it as soon as you try to run collectstatic. For example:

▶ ./manage.py collectstatic --noinput
Post-processed 'css/search.min.css' as 'css/search.min.css'
Post-processed 'css/base.min.css' as 'css/base.min.css'
Post-processed 'css/base-dynamic.min.css' as 'css/base-dynamic.min.css'
Post-processed 'js/google-analytics.min.js' as 'js/google-analytics.min.js'
Traceback (most recent call last):
...
django.core.exceptions.ImproperlyConfigured: Static file 'js/aplication.js' can not be found anywhere. Defined in PIPELINE['JAVASCRIPT']['stats']['source_filenames']

Final Thoughts

This was a morning hack. I'm still not entirely sure if this the best approach, but there was none better and the result is pretty good.

We run ./manage.py collectstatic --noinput in our continous integration just before it runs ./manage.py test. So if you make a Pull Request that has a typo in bundles.py it will get caught.

Unfortunately, it won't find missing files if you use foo*.js or something like that. django-pipeline uses glob.glob to convert expressions like that into a list of actual files and that depends on the filesystem and all of that happens before the django.contrib.staticfiles.finders.find function is called.

If you have any better suggestions to solve this, please let me know.

25 Jul 2017 12:12am GMT

Peter Bengtsson: Find static files defined in django-pipeline but not found

If you're reading this you're probably familiar with how, in django-pipeline, you define bundles of static files to be combined and served. If you're not familiar with django-pipeline it's unlike this'll be of much help.

The Challenge (aka. the pitfall)

So you specify bundles by creating things in your settings.py something like this:

PIPELINE = {
    'STYLESHEETS': {
        'colors': {
            'source_filenames': (
              'css/core.css',
              'css/colors/*.css',
              'css/layers.css'
            ),
            'output_filename': 'css/colors.css',
            'extra_context': {
                'media': 'screen,projection',
            },
        },
    },
    'JAVASCRIPT': {
        'stats': {
            'source_filenames': (
              'js/jquery.js',
              'js/d3.js',
              'js/collections/*.js',
              'js/aplication.js',
            ),
            'output_filename': 'js/stats.js',
        }
    }
}

You do a bit more configuration and now, when you run ./manage.py collectstatic --noinput Django and django-pipeline will gather up all static files from all Django apps installed, then start post processing then and doing things like concatenating them into one file and doing stuff like minification etc.

The problem is, if you look at the example snippet above, there's a typo. Instead of js/application.js it's accidentally js/aplication.js. Oh noes!!

What's sad is it that nobody will notice (running ./manage.py collectstatic will exit with a 0). At least not unless you do some careful manual reviewing. Perhaps you will notice later, when you've pushed the site to prod, that the output file js/stats.js actually doesn't contain the code from js/application.js.

Or, you can automate it!

A Solution (aka. the hack)

I started this work this morning because the error actually happened to us. Thankfully not in production but our staging server produced a rendered HTML page with <link href="/static/css/report.min.cd784b4a5e2d.css" rel="stylesheet" type="text/css" /> which was an actual file but it was 0 bytes.

It wasn't that hard to figure out what the problem was because of the context of recent changes but it would have been nice to catch this during continuous integration.

So what we did was add an extra class to settings.STATICFILES_FINDERS called myproject.base.finders.LeftoverPipelineFinder. So now it looks like this:

# in settings.py

STATICFILES_FINDERS = (
    'django.contrib.staticfiles.finders.FileSystemFinder',
    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    'pipeline.finders.PipelineFinder',
    'myproject.finders.LeftoverPipelineFinder',  # the new hotness!
)

And here's the class implementation:

from pipeline.finders import PipelineFinder

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured


class LeftoverPipelineFinder(PipelineFinder):
    """This finder is expected to come AFTER 
    django.contrib.staticfiles.finders.FileSystemFinder and 
    django.contrib.staticfiles.finders.AppDirectoriesFinder in 
    settings.STATICFILES_FINDERS.
    If a path is looked for here it means it's trying to find a file
    that none of the regular staticfiles finders couldn't find.
    """
    def find(self, path, all=False):
        # Before we raise an error, try to find out where,
        # in the bundles, this was defined. This will make it easier to correct
        # the mistake.
        for config_name in 'STYLESHEETS', 'JAVASCRIPT':
            config = settings.PIPELINE[config_name]
            for key in config:
                if path in config[key]['source_filenames']:
                    raise ImproperlyConfigured(
                        'Static file {!r} can not be found anywhere. Defined in '
                        "PIPELINE[{!r}][{!r}]['source_filenames']".format(
                            path,
                            config_name,
                            key,
                        )
                    )
        # If the file can't be found AND it's not in bundles, there's
        # got to be something else really wrong.
        raise NotImplementedError(path)

Now, if you have a typo or something in your bundles, you'll get a nice error about it as soon as you try to run collectstatic. For example:

▶ ./manage.py collectstatic --noinput
Post-processed 'css/search.min.css' as 'css/search.min.css'
Post-processed 'css/base.min.css' as 'css/base.min.css'
Post-processed 'css/base-dynamic.min.css' as 'css/base-dynamic.min.css'
Post-processed 'js/google-analytics.min.js' as 'js/google-analytics.min.js'
Traceback (most recent call last):
...
django.core.exceptions.ImproperlyConfigured: Static file 'js/aplication.js' can not be found anywhere. Defined in PIPELINE['JAVASCRIPT']['stats']['source_filenames']

Final Thoughts

This was a morning hack. I'm still not entirely sure if this the best approach, but there was none better and the result is pretty good.

We run ./manage.py collectstatic --noinput in our continous integration just before it runs ./manage.py test. So if you make a Pull Request that has a typo in bundles.py it will get caught.

Unfortunately, it won't find missing files if you use foo*.js or something like that. django-pipeline uses glob.glob to convert expressions like that into a list of actual files and that depends on the filesystem and all of that happens before the django.contrib.staticfiles.finders.find function is called.

If you have any better suggestions to solve this, please let me know.

25 Jul 2017 12:12am GMT

Daniel Bader: How to Install and Uninstall Python Packages Using Pip

How to Install and Uninstall Python Packages Using Pip

A step-by-step introduction to basic Python package management skills with the "pip" command. Learn how to install and remove third-party modules from PyPI.

How to Install and Uninstall Python Packages Using Pip

Python is approaching its third decade of good old age, and over the years many people have contributed to the creation of Python packages that perform specific functions and operations.

As of this writing, there are ~112K packages listed on the PyPI website. PyPI is short for "Python Package Index", a central repository for free third-party Python modules.

This large and convenient module ecosystem is what makes Python so great to work with:

You see, most Python programmers are really assemblers of Python packages, which take care of a big chunk of the programming load required by modern applications.

Chances are that there is more than one Python package ready to be unleashed and help you with your specific programming needs.

For instance, while reading dbader.org, you may notice that the pages on the site render emoji quite nicely. You may wonder…

I'd like to use emoji on my Python app!

Is there a Python package for that?

Let's find out!

Here's what we'll cover in this tutorial:

  1. Finding Python Packages
  2. What to Look for in a Python Package
  3. Installing Python Packages With Pip
  4. Capturing Installed Python Packages with Requirements Files
  5. Visualizing Installed Packages
  6. Installing Python Packages From a requirements.txt File
  7. Uninstalling Python Packages With Pip
  8. Summary & Conclusion

Finding Python Packages

Let's use the emoji use case as an example. We find emoji related Python packages by visiting the PyPI website and searching for emoji via the search box on the top right corner of the page.

As of this writing, PyPI lists 94 packages, of which a partial list is shown below.

dbader.org - installing and uninstalling Python packages with pip - emoji packages

Notice the "Weight*" header of the middle column. That's a key piece of information. The weight value is basically a search scoring number, which the site calculates for each package to rank them and list them accordingly.

If we read the footnote it tells us that the number is calculated by "the occurrence of search term weighted by field (name, summary, keywords, description, author, maintainer)."

Does that mean that the top one is the best package?

Not necessarily. Although uncommon, a package maintainer may stuff emoji into every field to try to top rank the package, which could well happen.

Conversely, many developers don't do their homework and don't bother filling out all the fields for their packages, which results in those packages being ranked lower.

You still need to research the packages listed, including a consideration for what your specific end use may be. For instance, a key question could be:

Which environment do you want to implement emoji on? A terminal-based app, or perhaps a Django web app?

If you are trying to display emoji on a django web app, you may be better off with the 10th package down the list shown above (package django-emoji 2.2.0).

For our use case, let's assume that we are interested in emoji for a terminal based Python app.

Let's check out the first one on our list (package emoji 0.4.5) by clicking on it.

What to Look for in a Python Package

The following are characteristics of a good Python package:

  1. Decent documentation: By reading it we can get a clue as to whether the package could meet our need or not;
  2. Maturity and stability: It's been around for some time, proven by both its age and its successive versions;
  3. Number of contributors: Healthy packages (especially complex ones) tend to have a healthy number of maintainers;
  4. Maintenance: It undergoes maintenance on a regular basis (we live in an ever-evolving world).

Although I would check it out, I wouldn't rely too much on the development status listed for each package, that is, whether it's a 4 - Beta or 5 - Production/Stable package. That classification is in the eye of the package creator and not necessarily reliable.

On our emoji example, the documentation seems decent. At the top of the page, we get a graphical indication of the package at work (see snippet below), which shows emoji on a Python interpreter. Yay!

dbader.org - installing and uninstalling Python packages with pip - emoji on a python interpreter

The documentation for our emoji package also tells us about installing it, how to contribute to its development, etc., and points us to a GitHub page for the package, which is a great source of useful information about it.

By visiting its GitHub page, we can glean from it that the package has been around for at least two years, was last maintained in the past couple of months, has been starred 300+ times, has been forked 58 times, and has 10 contributors.

It's looking good! We have identified a good candidate to incorporate emoji-ing into our Python terminal app.

How do we go about installing it?

Installing Python Packages With Pip

At this time, I am assuming that you already have Python installed on your system. There is plenty of info out there as to how to accomplish that.

Once you install Python, you can check whether pip is installed by running pip --version on a terminal.

I get the following output:

$ pip --version
pip 9.0.1 from /Library/Frameworks/Python.framework/↵
Versions/3.5/lib/python3.5/site-packages (python 3.5)

Since Python 3.4, pip is bundled with the Python installation package. If for some reason it is not installed, go ahead and get it installed.

I highly recommend also that you use a virtual environment (and more specifically, virtualenvwrapper), a set of extensions that…

…include wrappers for creating and deleting virtual environments and otherwise managing your development workflow, making it easier to work on more than one project at a time without introducing conflicts in their dependencies.

For this tutorial, I have created a virtual environment called pip-tutorial, which you will see going forward. My other tutorial walks you through setting up Python and virtualenvwrapper on Windows.

Below you'll see how package dependencies can bring complexity into our already complex development environments, which is the reason why using virtual environments is a must for Python development.

A great place to start learning about a terminal program is by running it without any options on the terminal. So, on your terminal, run pip. You would get a list of Commands and General Options.

Below is a partial list of the results on my terminal:

dbader.org - installing and uninstalling Python packages with pip - pip commands and general options

From there on you could run pip install --help to read on what the install command does and what you need to specify to run it, for example. Of course, reading the pip documentation is another great place to start.

$ pip install --help

Usage:
  pip install [options] <requirement specifier> [package-index-options] ...
  pip install [options] -r <requirements file> [package-index-options] ...
  pip install [options] [-e] <vcs project url> ...
  pip install [options] [-e] <local project path> ...
  pip install [options] <archive url/path> ...

Description:
  Install packages from:

  - PyPI (and other indexes) using requirement specifiers.
  - VCS project urls.
  - Local project directories.
  - Local or remote source archives.

  pip also supports installing from "requirements files", which provide
  an easy way to specify a whole environment to be installed.

Install Options:
  ...

Let's take a quick detour and focus on the freeze command next, which will be a key one in dealing with dependencies. Running pip freeze displays a list of all installed Python packages. If I run it with my freshly installed virtual environment active, I should get an empty list, which is the case:

$ pip freeze

Now we can get the Python interpreter going by typing python on our terminal. Once that's done, let's try to import the emoji module, upon which python will complain that there isn't such a module installed, and rightfully so for we haven't installed it, yet:

$ python
Python 3.5.0 (default)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import emoji
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'emoji'

To finally install the package, we can go ahead and run pip install emoji on our terminal. I get the following output:

$ pip install emoji==0.4.5
Collecting emoji==0.4.5
Installing collected packages: emoji
Successfully installed emoji-0.4.5

🚫 Getting a pip install "invalid syntax" error?

Please note that the pip install command needs to be run from the command-line inside your terminal program, and not inside the Python interpreter.

If you're getting a "SyntaxError: invalid syntax" message from running pip install, then try leaving the interpreter with Ctrl+C and run the pip command again from the terminal prompt.

Pip is a program that installs modules, so you can use them from Python. Once you have installed the module, then you can open the Python shell and import the module.

When installing packages with pip, we can constrain pip to install a version of our preference, by using the following operators:

A specific version of the package (==):

$ pip install emoji==0.4.1

A version other than the specified one (!=):

$ pip install emoji!=0.4.1

A version equal to or greater than a specific version (>=):

$ pip install emoji>=0.4.0

A version of the package in the specified range (>=X.Y.T, <=X.Y.Z):

$ pip install emoji>=0.4.0, <=0.4.9

For a full specification of the version specifiers, refer to this page. Generally the most useful specifier here is == to pip install a specific version of a package. If we don't constrain pip, it will grab the latest version of the package.

You may be wondering why you would want to install an older version of a Python package in the first place:

Programmers freeze requirements to keep track of the versions of the different packages that are installed on development and production environments. One of the objectives is to be able to replicate the environments as needed. Dan's course on Python dependency management goes into more detail on that topic.

Let's continue on and run pip freeze again after installing the emoji package. You should now see it included in the list of all installed Python modules:

$ pip freeze
emoji==0.4.5

As expected, pip freeze now lists the emoji package as an added dependency with a specific version number.

I now go back to my Python interpreter session, and run import emoji, and this time around Python doesn't complain, which is a good sign. I test it, and get the following output:

dbader.org - installing and uninstalling Python packages with pip - emoji works

Success, at last! We just installed and then imported a third-party Python module. Great job 🙂

It's typical for an application to have several interdependent packages. For instance, running pip freeze on the virtual environment that I use to develop tumblingprogrammer.com, will output the following list of modules:

appdirs==1.4.3
beautifulsoup4==4.6.0
Django==1.11.1
django-bootstrap3==8.2.3
django-crispy-forms==1.6.1
django-debug-toolbar==1.8
(...)
pyparsing==2.2.0
pytz==2017.2
PyYAML==3.12
selenium==3.4.1
six==1.10.0
sqlparse==0.2.3
tornado==4.5.1

That's a total of 25 Python packages. And it's a fairly simple application. Later on I'll describe a way to visualize the interdependency between packages.

Capturing Installed Python Packages with Requirements Files

Developers get in the habit of freezing requirements every time that a package or a dependency gets installed on their projects. We do that by running the following pip command:

$ pip freeze > requirements.txt

This dumps the output of pip freeze into a requirements.txt file on the working directory.

Let's assume now that for some reason we need to install MarkupSafe version 0.11. Let's assume also that we have gotten ahead, installed it, tested it, and that our app behaves as we expect it to.

Let's run pip freeze, which would only output our two packages, as shown below:

$ pip freeze
emoji==0.4.5
MarkupSafe==0.11

To continue with our learning, let's go ahead and install Flask, a popular web microframework. We'll grab the latest version of it by running pip install flask.

I get the following output (if you are following along, yours might differ a little bit, for my computer had cached the files from a previous install):

$ pip install flask
Collecting flask
  Using cached Flask-0.12.2-py2.py3-none-any.whl
Collecting itsdangerous>=0.21 (from flask)
Collecting Jinja2>=2.4 (from flask)
  Using cached Jinja2-2.9.6-py2.py3-none-any.whl
Collecting click>=2.0 (from flask)
  Using cached click-6.7-py2.py3-none-any.whl
Collecting Werkzeug>=0.7 (from flask)
  Using cached Werkzeug-0.12.2-py2.py3-none-any.whl
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->flask)
Installing collected packages: itsdangerous, MarkupSafe, Jinja2, click, Werkzeug, flask
  Found existing installation: MarkupSafe 0.11
    Uninstalling MarkupSafe-0.11:
      Successfully uninstalled MarkupSafe-0.11
Successfully installed Jinja2-2.9.6 MarkupSafe-1.0 Werkzeug-0.12.2 click-6.7 flask-0.12.2 itsdangerous-0.24

Flask, being a more complex package, has some dependencies (Werkzeug, itsdangerous, etc.) which are installed with it automatically through the pip install command.

I want to call your attention to the following lines, extracted from the above listing:

...
  Found existing installation: MarkupSafe 0.11
    Uninstalling MarkupSafe-0.11:
      Successfully uninstalled MarkupSafe-0.11
...

Take a close look…

You'll see that pip doesn't have a way of reconciling conflicting dependencies. Without even warning us, it went ahead and replaced version 0.11 with version 1.0 of our MarkupSafe package. And that could be trouble for our application.

At that point in time, we run our app tests (assuming that have them), and dig into our application to make sure that the changes between 0.11 and 1.0 of the MarkupSafe package don't break it.

If I were to face this situation in real life, I would roll back the changes first by uninstalling Flask and its dependencies and restore the packages that I had before. Then I would upgrade MarkupSafe to 1.0, test to make sure that the application works as expected. And then-and only then-would I re-install Flask.

Assuming that we have gone through rolling back, upgrading, testing, and re-installing Flask, if we run pip freeze now, we get 7 packages in total:

$ pip freeze
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
MarkupSafe==1.0
Werkzeug==0.12.2

Let's go ahead and freeze our requirements into a requirements.txt file by running pip freeze > requirements.txt.

Now we're going to add another package with dependencies to increase the complexity of our setup. We'll install version 6.0 of a package called alembic by running:

$ pip install alembic==0.6
Collecting alembic==0.6
Collecting Mako (from alembic==0.6)
Collecting SQLAlchemy>=0.7.3 (from alembic==0.6)
Requirement already satisfied: MarkupSafe>=0.9.2 in /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages (from Mako->alembic==0.6)
Installing collected packages: Mako, SQLAlchemy, alembic
Successfully installed Mako-1.0.7 SQLAlchemy-1.1.11 alembic-0.6.0

I now call your attention to the following line from the above listing:

...
Requirement already satisfied: MarkupSafe>=0.9.2 in /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages (from Mako->alembic==0.6)
...

Which means that alembic also depends on MarkupSafe. More complexity, huh? Let's run pip freeze:

$ pip freeze
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
SQLAlchemy==1.1.11
Werkzeug==0.12.2

The listing above showing all the packages on our emoji application is not very helpful at the moment, for it doesn't give us info on dependencies (it only lists packages in alphabetical order). Let's fix that.

Visualizing Installed Packages

One good package to have installed on our environment is pipdeptree, which shows the dependency tree of packages. Let's go ahead and install the latest version of it by running the following command:

$ pip install pipdeptree

Once it's done, let's run pip freeze to see what we get:

$ pip freeze
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
pipdeptree==0.10.1
SQLAlchemy==1.1.11
Werkzeug==0.12.2

We now get 11 packages, as we have added pipdeptree, which had no dependencies. Let's run pipdeptree on the terminal to see what it does. Below is the output that I get on my machine:

$ pipdeptree
alembic==0.6.0
  - Mako [required: Any, installed: 1.0.7]
    - MarkupSafe [required: >=0.9.2, installed: 1.0]
  - SQLAlchemy [required: >=0.7.3, installed: 1.1.11]
emoji==0.4.5
Flask==0.12.2
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.9.6]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.12.2]
pipdeptree==0.10.1
  - pip [required: >=6.0.0, installed: 9.0.1]
setuptools==36.2.0
wheel==0.29.0

We notice much more useful information here, including dependencies, and the minimum versions required for dependent packages to work properly.

Notice, once again, how MarkupSafe is listed twice, as both Jinja2 (and Flask) and Mako (and alembic) depend on it. That's very useful information to troubleshoot things gone ugly.

We also notice other packages here that pip freeze doesn't list, including pip, setuptools and wheel. The reason is that by default pip freeze doesn't list packages that pip itself depends on.

We can use the --all flag to show also those packages. Let's test this by running pip freeze --all, in which case we get:

$ pip freeze --all
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
pip==9.0.1
pipdeptree==0.10.1
setuptools==36.2.0
SQLAlchemy==1.1.11
Werkzeug==0.12.2
wheel==0.29.0

Another benefit of using pipdeptree is that it warns us about conflicting dependencies, including circular ones (where packages depend on one another), but I have yet to see that in action. So far I couldn't replicate the functionality on my system. You can find more info about the tool on its PyPI page.

Installing Python Packages From a requirements.txt File

If you have a requirements.txt file, you can install all the packages listed there by running the following command:

$ pip install -r /path/to/the/file/requirements.txt

This is very handy when we want to replicate environments and have access to a requirements.txt that reflects the makeup of it.

Uninstalling Python Packages With Pip

In this section you'll see how to uninstall individual Python packages from your system or active virtual environment, how you can remove multiple packages at once with a single command, and how you can remove all installed Python packages.

Uninstalling individual packages:

You can do so by running, as an example, pip uninstall alembic. Let's do that on our setup to see what happens. Here is the output on my end:

$ pip uninstall alembic
Uninstalling alembic-0.6.0:
  /Users/puma/.virtualenvs/pip-tutorial/bin/alembic
  ... a bunch on other files ...
  /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages/alembic/util.py
Proceed (y/n)? y
  Successfully uninstalled alembic-0.6.0

Let's run pipdeptree to see what our setup looks like:

$ pipdeptree
emoji==0.4.5
Flask==0.12.2
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.9.6]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.12.2]
Mako==1.0.7
  - MarkupSafe [required: >=0.9.2, installed: 1.0]
pipdeptree==0.10.1
  - pip [required: >=6.0.0, installed: 9.0.1]
setuptools==36.2.0
SQLAlchemy==1.1.11
wheel==0.29.0

If you look carefully, you may notice that the alembic dependencies are still present, because pip uninstall does not get rid of them, by design.

We have to manually do that (there are other options, which we will cover below). Therefore, it is extremely important that we freeze our requirements and commit changes to our requirements.txt file every time that we install or uninstall packages so we know what our setup should look like if we need to roll back changes.

Uninstalling multiple Python packages at once:

You can also uninstall several packages at once, by using the following command-line syntax:

$ pip uninstall package1 package2 ...

Another option is reading the list of packages to uninstall from a requirements file. Similar to its install counterpart, if you have a requirements.txt file, you can uninstall all the packages listed there like so:

$ pip uninstall -r /path/to/the/file/requirements.txt

Note that we could wipe out all the packages on our setup, which could actually be quite useful. Let's take a look at an example.

The output below is a list of my git commits log (gl is an alias on my bash profile for a prettified git log):

$ gl
* 40f4f37 - (HEAD -> master) all packages in (37 minutes ago) <Jose Pumar>
* 2d00cf5 - emoji + markupsafe + flask + alembic (56 minutes ago) <Jose Pumar>
* e52002b - emoji + MarkupSafe + Flask (84 minutes ago) <Jose Pumar>
* 9c48895 - emoji + MarkupSafe (86 minutes ago) <Jose Pumar>
* 3a797b3 - emoji + MarkSafe (2 hours ago) <Jose Pumar>
* ... other commits...

If I change my mind and decide that I don't need alembic any more, I could delete all the packages by running pip uninstall -r requirements.txt while on commit 40f4f37 (the HEAD).

If I do it, it gives me a bunch of warnings and asks me if I want to proceed several times (once for each package), to which I say yes. I could have avoided that by using the flag -y, as in:

$ pip uninstall -y -r requirements.txt

The -y flag tells pip not to ask for confirmation of uninstall deletions. If we run pip freeze after this operation, we'll get an empty packages list, which is what we want.

We then checkout commit e52002b (the last safe commit before we installed alembic), and run pip install -r requirements.txt to reinstate the packages that we had at that point in time.

Removing all installed Python packages:

Sometimes it can be useful to remove all installed packages in a virtual environment or on your system Python install. It can help you get back to a clean slate.

Running the following command will uninstall all Python packages in the currently active environment:

$ pip freeze | xargs pip uninstall -y

This command works by first listing all installed packages using the freeze command, and then feeding the list of packages into the pip uninstall command to remove them.

Adding the -y flag automatically confirms the uninstallation so you don't have to stick around hammering the "y" key on your keyboard.

Installing and Uninstalling Python Packages with the "pip" Package Manager - Conclusion

Although we covered a lot of ground and shed light on key commands and major challenges that you may face when dealing with installing and uninstalling Python packages and their dependencies.

In summary, the workflow for the installation of a Python package with pip is as follows:

  1. Make sure that you are using a virtual environment.
  2. Identify the need for a new package.
  3. Research potential candidate packages: Look for the maturity of the package, its documentation, etc. See what you can find regarding its dependencies. For example, other packages that have to be installed so the package works properly. Sometimes the documentation refers to them.
  4. Install the package and its dependent packages: pip will do this for you. Look for version upgrades in the pip installation log.
  5. Test your application to make sure that the package meets your needs and that the package and or its dependent packages don't break it.
  6. Freeze your requirements: Run pip freeze > requirements.txt if tests show your application is still okay and works as intended.
  7. Commit the changes to Git or the version control tool of your choice.
  8. Repeat.

There is a lot more to cover, especially when it comes to dependency management, which has long-term implications on how we setup and configure our Python projects.

Such a complexity is one of the factors that make necessary to implement different settings and configurations to account for the distinct needs of our development, staging, and production environments.

Happy pip-ing!

25 Jul 2017 12:00am GMT

Daniel Bader: How to Install and Uninstall Python Packages Using Pip

How to Install and Uninstall Python Packages Using Pip

A step-by-step introduction to basic Python package management skills with the "pip" command. Learn how to install and remove third-party modules from PyPI.

How to Install and Uninstall Python Packages Using Pip

Python is approaching its third decade of good old age, and over the years many people have contributed to the creation of Python packages that perform specific functions and operations.

As of this writing, there are ~112K packages listed on the PyPI website. PyPI is short for "Python Package Index", a central repository for free third-party Python modules.

This large and convenient module ecosystem is what makes Python so great to work with:

You see, most Python programmers are really assemblers of Python packages, which take care of a big chunk of the programming load required by modern applications.

Chances are that there is more than one Python package ready to be unleashed and help you with your specific programming needs.

For instance, while reading dbader.org, you may notice that the pages on the site render emoji quite nicely. You may wonder…

I'd like to use emoji on my Python app!

Is there a Python package for that?

Let's find out!

Here's what we'll cover in this tutorial:

  1. Finding Python Packages
  2. What to Look for in a Python Package
  3. Installing Python Packages With Pip
  4. Capturing Installed Python Packages with Requirements Files
  5. Visualizing Installed Packages
  6. Installing Python Packages From a requirements.txt File
  7. Uninstalling Python Packages With Pip
  8. Summary & Conclusion

Finding Python Packages

Let's use the emoji use case as an example. We find emoji related Python packages by visiting the PyPI website and searching for emoji via the search box on the top right corner of the page.

As of this writing, PyPI lists 94 packages, of which a partial list is shown below.

dbader.org - installing and uninstalling Python packages with pip - emoji packages

Notice the "Weight*" header of the middle column. That's a key piece of information. The weight value is basically a search scoring number, which the site calculates for each package to rank them and list them accordingly.

If we read the footnote it tells us that the number is calculated by "the occurrence of search term weighted by field (name, summary, keywords, description, author, maintainer)."

Does that mean that the top one is the best package?

Not necessarily. Although uncommon, a package maintainer may stuff emoji into every field to try to top rank the package, which could well happen.

Conversely, many developers don't do their homework and don't bother filling out all the fields for their packages, which results in those packages being ranked lower.

You still need to research the packages listed, including a consideration for what your specific end use may be. For instance, a key question could be:

Which environment do you want to implement emoji on? A terminal-based app, or perhaps a Django web app?

If you are trying to display emoji on a django web app, you may be better off with the 10th package down the list shown above (package django-emoji 2.2.0).

For our use case, let's assume that we are interested in emoji for a terminal based Python app.

Let's check out the first one on our list (package emoji 0.4.5) by clicking on it.

What to Look for in a Python Package

The following are characteristics of a good Python package:

  1. Decent documentation: By reading it we can get a clue as to whether the package could meet our need or not;
  2. Maturity and stability: It's been around for some time, proven by both its age and its successive versions;
  3. Number of contributors: Healthy packages (especially complex ones) tend to have a healthy number of maintainers;
  4. Maintenance: It undergoes maintenance on a regular basis (we live in an ever-evolving world).

Although I would check it out, I wouldn't rely too much on the development status listed for each package, that is, whether it's a 4 - Beta or 5 - Production/Stable package. That classification is in the eye of the package creator and not necessarily reliable.

On our emoji example, the documentation seems decent. At the top of the page, we get a graphical indication of the package at work (see snippet below), which shows emoji on a Python interpreter. Yay!

dbader.org - installing and uninstalling Python packages with pip - emoji on a python interpreter

The documentation for our emoji package also tells us about installing it, how to contribute to its development, etc., and points us to a GitHub page for the package, which is a great source of useful information about it.

By visiting its GitHub page, we can glean from it that the package has been around for at least two years, was last maintained in the past couple of months, has been starred 300+ times, has been forked 58 times, and has 10 contributors.

It's looking good! We have identified a good candidate to incorporate emoji-ing into our Python terminal app.

How do we go about installing it?

Installing Python Packages With Pip

At this time, I am assuming that you already have Python installed on your system. There is plenty of info out there as to how to accomplish that.

Once you install Python, you can check whether pip is installed by running pip --version on a terminal.

I get the following output:

$ pip --version
pip 9.0.1 from /Library/Frameworks/Python.framework/↵
Versions/3.5/lib/python3.5/site-packages (python 3.5)

Since Python 3.4, pip is bundled with the Python installation package. If for some reason it is not installed, go ahead and get it installed.

I highly recommend also that you use a virtual environment (and more specifically, virtualenvwrapper), a set of extensions that…

…include wrappers for creating and deleting virtual environments and otherwise managing your development workflow, making it easier to work on more than one project at a time without introducing conflicts in their dependencies.

For this tutorial, I have created a virtual environment called pip-tutorial, which you will see going forward. My other tutorial walks you through setting up Python and virtualenvwrapper on Windows.

Below you'll see how package dependencies can bring complexity into our already complex development environments, which is the reason why using virtual environments is a must for Python development.

A great place to start learning about a terminal program is by running it without any options on the terminal. So, on your terminal, run pip. You would get a list of Commands and General Options.

Below is a partial list of the results on my terminal:

dbader.org - installing and uninstalling Python packages with pip - pip commands and general options

From there on you could run pip install --help to read on what the install command does and what you need to specify to run it, for example. Of course, reading the pip documentation is another great place to start.

$ pip install --help

Usage:
  pip install [options] <requirement specifier> [package-index-options] ...
  pip install [options] -r <requirements file> [package-index-options] ...
  pip install [options] [-e] <vcs project url> ...
  pip install [options] [-e] <local project path> ...
  pip install [options] <archive url/path> ...

Description:
  Install packages from:

  - PyPI (and other indexes) using requirement specifiers.
  - VCS project urls.
  - Local project directories.
  - Local or remote source archives.

  pip also supports installing from "requirements files", which provide
  an easy way to specify a whole environment to be installed.

Install Options:
  ...

Let's take a quick detour and focus on the freeze command next, which will be a key one in dealing with dependencies. Running pip freeze displays a list of all installed Python packages. If I run it with my freshly installed virtual environment active, I should get an empty list, which is the case:

$ pip freeze

Now we can get the Python interpreter going by typing python on our terminal. Once that's done, let's try to import the emoji module, upon which python will complain that there isn't such a module installed, and rightfully so for we haven't installed it, yet:

$ python
Python 3.5.0 (default)
[GCC 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import emoji
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'emoji'

To finally install the package, we can go ahead and run pip install emoji on our terminal. I get the following output:

$ pip install emoji==0.4.5
Collecting emoji==0.4.5
Installing collected packages: emoji
Successfully installed emoji-0.4.5

🚫 Getting a pip install "invalid syntax" error?

Please note that the pip install command needs to be run from the command-line inside your terminal program, and not inside the Python interpreter.

If you're getting a "SyntaxError: invalid syntax" message from running pip install, then try leaving the interpreter with Ctrl+C and run the pip command again from the terminal prompt.

Pip is a program that installs modules, so you can use them from Python. Once you have installed the module, then you can open the Python shell and import the module.

When installing packages with pip, we can constrain pip to install a version of our preference, by using the following operators:

A specific version of the package (==):

$ pip install emoji==0.4.1

A version other than the specified one (!=):

$ pip install emoji!=0.4.1

A version equal to or greater than a specific version (>=):

$ pip install emoji>=0.4.0

A version of the package in the specified range (>=X.Y.T, <=X.Y.Z):

$ pip install emoji>=0.4.0, <=0.4.9

For a full specification of the version specifiers, refer to this page. Generally the most useful specifier here is == to pip install a specific version of a package. If we don't constrain pip, it will grab the latest version of the package.

You may be wondering why you would want to install an older version of a Python package in the first place:

Programmers freeze requirements to keep track of the versions of the different packages that are installed on development and production environments. One of the objectives is to be able to replicate the environments as needed. Dan's course on Python dependency management goes into more detail on that topic.

Let's continue on and run pip freeze again after installing the emoji package. You should now see it included in the list of all installed Python modules:

$ pip freeze
emoji==0.4.5

As expected, pip freeze now lists the emoji package as an added dependency with a specific version number.

I now go back to my Python interpreter session, and run import emoji, and this time around Python doesn't complain, which is a good sign. I test it, and get the following output:

dbader.org - installing and uninstalling Python packages with pip - emoji works

Success, at last! We just installed and then imported a third-party Python module. Great job 🙂

It's typical for an application to have several interdependent packages. For instance, running pip freeze on the virtual environment that I use to develop tumblingprogrammer.com, will output the following list of modules:

appdirs==1.4.3
beautifulsoup4==4.6.0
Django==1.11.1
django-bootstrap3==8.2.3
django-crispy-forms==1.6.1
django-debug-toolbar==1.8
(...)
pyparsing==2.2.0
pytz==2017.2
PyYAML==3.12
selenium==3.4.1
six==1.10.0
sqlparse==0.2.3
tornado==4.5.1

That's a total of 25 Python packages. And it's a fairly simple application. Later on I'll describe a way to visualize the interdependency between packages.

Capturing Installed Python Packages with Requirements Files

Developers get in the habit of freezing requirements every time that a package or a dependency gets installed on their projects. We do that by running the following pip command:

$ pip freeze > requirements.txt

This dumps the output of pip freeze into a requirements.txt file on the working directory.

Let's assume now that for some reason we need to install MarkupSafe version 0.11. Let's assume also that we have gotten ahead, installed it, tested it, and that our app behaves as we expect it to.

Let's run pip freeze, which would only output our two packages, as shown below:

$ pip freeze
emoji==0.4.5
MarkupSafe==0.11

To continue with our learning, let's go ahead and install Flask, a popular web microframework. We'll grab the latest version of it by running pip install flask.

I get the following output (if you are following along, yours might differ a little bit, for my computer had cached the files from a previous install):

$ pip install flask
Collecting flask
  Using cached Flask-0.12.2-py2.py3-none-any.whl
Collecting itsdangerous>=0.21 (from flask)
Collecting Jinja2>=2.4 (from flask)
  Using cached Jinja2-2.9.6-py2.py3-none-any.whl
Collecting click>=2.0 (from flask)
  Using cached click-6.7-py2.py3-none-any.whl
Collecting Werkzeug>=0.7 (from flask)
  Using cached Werkzeug-0.12.2-py2.py3-none-any.whl
Collecting MarkupSafe>=0.23 (from Jinja2>=2.4->flask)
Installing collected packages: itsdangerous, MarkupSafe, Jinja2, click, Werkzeug, flask
  Found existing installation: MarkupSafe 0.11
    Uninstalling MarkupSafe-0.11:
      Successfully uninstalled MarkupSafe-0.11
Successfully installed Jinja2-2.9.6 MarkupSafe-1.0 Werkzeug-0.12.2 click-6.7 flask-0.12.2 itsdangerous-0.24

Flask, being a more complex package, has some dependencies (Werkzeug, itsdangerous, etc.) which are installed with it automatically through the pip install command.

I want to call your attention to the following lines, extracted from the above listing:

...
  Found existing installation: MarkupSafe 0.11
    Uninstalling MarkupSafe-0.11:
      Successfully uninstalled MarkupSafe-0.11
...

Take a close look…

You'll see that pip doesn't have a way of reconciling conflicting dependencies. Without even warning us, it went ahead and replaced version 0.11 with version 1.0 of our MarkupSafe package. And that could be trouble for our application.

At that point in time, we run our app tests (assuming that have them), and dig into our application to make sure that the changes between 0.11 and 1.0 of the MarkupSafe package don't break it.

If I were to face this situation in real life, I would roll back the changes first by uninstalling Flask and its dependencies and restore the packages that I had before. Then I would upgrade MarkupSafe to 1.0, test to make sure that the application works as expected. And then-and only then-would I re-install Flask.

Assuming that we have gone through rolling back, upgrading, testing, and re-installing Flask, if we run pip freeze now, we get 7 packages in total:

$ pip freeze
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
MarkupSafe==1.0
Werkzeug==0.12.2

Let's go ahead and freeze our requirements into a requirements.txt file by running pip freeze > requirements.txt.

Now we're going to add another package with dependencies to increase the complexity of our setup. We'll install version 6.0 of a package called alembic by running:

$ pip install alembic==0.6
Collecting alembic==0.6
Collecting Mako (from alembic==0.6)
Collecting SQLAlchemy>=0.7.3 (from alembic==0.6)
Requirement already satisfied: MarkupSafe>=0.9.2 in /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages (from Mako->alembic==0.6)
Installing collected packages: Mako, SQLAlchemy, alembic
Successfully installed Mako-1.0.7 SQLAlchemy-1.1.11 alembic-0.6.0

I now call your attention to the following line from the above listing:

...
Requirement already satisfied: MarkupSafe>=0.9.2 in /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages (from Mako->alembic==0.6)
...

Which means that alembic also depends on MarkupSafe. More complexity, huh? Let's run pip freeze:

$ pip freeze
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
SQLAlchemy==1.1.11
Werkzeug==0.12.2

The listing above showing all the packages on our emoji application is not very helpful at the moment, for it doesn't give us info on dependencies (it only lists packages in alphabetical order). Let's fix that.

Visualizing Installed Packages

One good package to have installed on our environment is pipdeptree, which shows the dependency tree of packages. Let's go ahead and install the latest version of it by running the following command:

$ pip install pipdeptree

Once it's done, let's run pip freeze to see what we get:

$ pip freeze
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
pipdeptree==0.10.1
SQLAlchemy==1.1.11
Werkzeug==0.12.2

We now get 11 packages, as we have added pipdeptree, which had no dependencies. Let's run pipdeptree on the terminal to see what it does. Below is the output that I get on my machine:

$ pipdeptree
alembic==0.6.0
  - Mako [required: Any, installed: 1.0.7]
    - MarkupSafe [required: >=0.9.2, installed: 1.0]
  - SQLAlchemy [required: >=0.7.3, installed: 1.1.11]
emoji==0.4.5
Flask==0.12.2
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.9.6]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.12.2]
pipdeptree==0.10.1
  - pip [required: >=6.0.0, installed: 9.0.1]
setuptools==36.2.0
wheel==0.29.0

We notice much more useful information here, including dependencies, and the minimum versions required for dependent packages to work properly.

Notice, once again, how MarkupSafe is listed twice, as both Jinja2 (and Flask) and Mako (and alembic) depend on it. That's very useful information to troubleshoot things gone ugly.

We also notice other packages here that pip freeze doesn't list, including pip, setuptools and wheel. The reason is that by default pip freeze doesn't list packages that pip itself depends on.

We can use the --all flag to show also those packages. Let's test this by running pip freeze --all, in which case we get:

$ pip freeze --all
alembic==0.6.0
click==6.7
emoji==0.4.5
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.9.6
Mako==1.0.7
MarkupSafe==1.0
pip==9.0.1
pipdeptree==0.10.1
setuptools==36.2.0
SQLAlchemy==1.1.11
Werkzeug==0.12.2
wheel==0.29.0

Another benefit of using pipdeptree is that it warns us about conflicting dependencies, including circular ones (where packages depend on one another), but I have yet to see that in action. So far I couldn't replicate the functionality on my system. You can find more info about the tool on its PyPI page.

Installing Python Packages From a requirements.txt File

If you have a requirements.txt file, you can install all the packages listed there by running the following command:

$ pip install -r /path/to/the/file/requirements.txt

This is very handy when we want to replicate environments and have access to a requirements.txt that reflects the makeup of it.

Uninstalling Python Packages With Pip

In this section you'll see how to uninstall individual Python packages from your system or active virtual environment, how you can remove multiple packages at once with a single command, and how you can remove all installed Python packages.

Uninstalling individual packages:

You can do so by running, as an example, pip uninstall alembic. Let's do that on our setup to see what happens. Here is the output on my end:

$ pip uninstall alembic
Uninstalling alembic-0.6.0:
  /Users/puma/.virtualenvs/pip-tutorial/bin/alembic
  ... a bunch on other files ...
  /Users/puma/.virtualenvs/pip-tutorial/lib/python3.5/site-packages/alembic/util.py
Proceed (y/n)? y
  Successfully uninstalled alembic-0.6.0

Let's run pipdeptree to see what our setup looks like:

$ pipdeptree
emoji==0.4.5
Flask==0.12.2
  - click [required: >=2.0, installed: 6.7]
  - itsdangerous [required: >=0.21, installed: 0.24]
  - Jinja2 [required: >=2.4, installed: 2.9.6]
    - MarkupSafe [required: >=0.23, installed: 1.0]
  - Werkzeug [required: >=0.7, installed: 0.12.2]
Mako==1.0.7
  - MarkupSafe [required: >=0.9.2, installed: 1.0]
pipdeptree==0.10.1
  - pip [required: >=6.0.0, installed: 9.0.1]
setuptools==36.2.0
SQLAlchemy==1.1.11
wheel==0.29.0

If you look carefully, you may notice that the alembic dependencies are still present, because pip uninstall does not get rid of them, by design.

We have to manually do that (there are other options, which we will cover below). Therefore, it is extremely important that we freeze our requirements and commit changes to our requirements.txt file every time that we install or uninstall packages so we know what our setup should look like if we need to roll back changes.

Uninstalling multiple Python packages at once:

You can also uninstall several packages at once, by using the following command-line syntax:

$ pip uninstall package1 package2 ...

Another option is reading the list of packages to uninstall from a requirements file. Similar to its install counterpart, if you have a requirements.txt file, you can uninstall all the packages listed there like so:

$ pip uninstall -r /path/to/the/file/requirements.txt

Note that we could wipe out all the packages on our setup, which could actually be quite useful. Let's take a look at an example.

The output below is a list of my git commits log (gl is an alias on my bash profile for a prettified git log):

$ gl
* 40f4f37 - (HEAD -> master) all packages in (37 minutes ago) <Jose Pumar>
* 2d00cf5 - emoji + markupsafe + flask + alembic (56 minutes ago) <Jose Pumar>
* e52002b - emoji + MarkupSafe + Flask (84 minutes ago) <Jose Pumar>
* 9c48895 - emoji + MarkupSafe (86 minutes ago) <Jose Pumar>
* 3a797b3 - emoji + MarkSafe (2 hours ago) <Jose Pumar>
* ... other commits...

If I change my mind and decide that I don't need alembic any more, I could delete all the packages by running pip uninstall -r requirements.txt while on commit 40f4f37 (the HEAD).

If I do it, it gives me a bunch of warnings and asks me if I want to proceed several times (once for each package), to which I say yes. I could have avoided that by using the flag -y, as in:

$ pip uninstall -y -r requirements.txt

The -y flag tells pip not to ask for confirmation of uninstall deletions. If we run pip freeze after this operation, we'll get an empty packages list, which is what we want.

We then checkout commit e52002b (the last safe commit before we installed alembic), and run pip install -r requirements.txt to reinstate the packages that we had at that point in time.

Removing all installed Python packages:

Sometimes it can be useful to remove all installed packages in a virtual environment or on your system Python install. It can help you get back to a clean slate.

Running the following command will uninstall all Python packages in the currently active environment:

$ pip freeze | xargs pip uninstall -y

This command works by first listing all installed packages using the freeze command, and then feeding the list of packages into the pip uninstall command to remove them.

Adding the -y flag automatically confirms the uninstallation so you don't have to stick around hammering the "y" key on your keyboard.

Installing and Uninstalling Python Packages with the "pip" Package Manager - Conclusion

Although we covered a lot of ground and shed light on key commands and major challenges that you may face when dealing with installing and uninstalling Python packages and their dependencies.

In summary, the workflow for the installation of a Python package with pip is as follows:

  1. Make sure that you are using a virtual environment.
  2. Identify the need for a new package.
  3. Research potential candidate packages: Look for the maturity of the package, its documentation, etc. See what you can find regarding its dependencies. For example, other packages that have to be installed so the package works properly. Sometimes the documentation refers to them.
  4. Install the package and its dependent packages: pip will do this for you. Look for version upgrades in the pip installation log.
  5. Test your application to make sure that the package meets your needs and that the package and or its dependent packages don't break it.
  6. Freeze your requirements: Run pip freeze > requirements.txt if tests show your application is still okay and works as intended.
  7. Commit the changes to Git or the version control tool of your choice.
  8. Repeat.

There is a lot more to cover, especially when it comes to dependency management, which has long-term implications on how we setup and configure our Python projects.

Such a complexity is one of the factors that make necessary to implement different settings and configurations to account for the distinct needs of our development, staging, and production environments.

Happy pip-ing!

25 Jul 2017 12:00am GMT

24 Jul 2017

feedPlanet Python

Python Anywhere: Outage report: 20, 21 and 22 July 2017

We had several outages over the last few days. The problem appears to be fixed now, but investigations into the underlying cause are still underway. This post is a summary of what happened, and what we know so far. Once we've got a better understanding of the issue, we'll post more.

It's worth saying at the outset that while the problems related to the way we manage our users' files, those files themselves were always safe. While availability problems are clearly a big issue, we regard data integrity as more important.

20 July: the system update

On Thursday 20 July, at 05:00 UTC, we released a new system update for PythonAnywhere. This was largely an infrastructural update. In particular, we updated our file servers from Ubuntu 14.04 to 16.04, as part of a general upgrade of all servers in our cluster.

File servers are, of course, the servers that manage the files in your PythonAnywhere disk storage. Each server handles the data for a specific set of users, and serves the files up to the other servers in the cluster that need them -- the "execution" servers where your websites, your scheduled tasks, and your consoles run. The files themselves are stored on network-attached storage (and mirrored in realtime to redundant disks on a separate set of backup servers); the file servers simply act as NFS servers and manage a few simple things like disk quotas.

While the system update took a little longer than we'd planned, once everything was up and running, the system looked stable and all monitoring looked good.

20 July: initial problems

At 12:07 UTC our monitoring system showed a very brief issue. From some of our web servers, it appeared that access to one of our file servers, file-2, had very briefly slowed right down -- it was taking more than 30 seconds to list the specific directory that is monitored. The problem cleared up after about 60 seconds. Other file servers were completely unaffected. We did some investigations, but couldn't find anything, so we chalked it up as a glitch and kept an eye out for further problems.

At 14:12 UTC it happened again, and then over the course of the afternoon, the "glitches" became more frequent and started lasting longer. We discovered that the symptom from the file server's side was that all of the NFS daemons -- the processes that together make up an NFS server -- would all become busy; system load would rise from about 1.5 to 64 or so. They were all waiting uninterruptably on what we think was disk I/O (status "D" in top).

The problem only affected file-2 -- other file servers were all fine. Given that every file server had been upgraded to an identical system image, our initial suspicion was that there might be some kind of hardware problem. At 17:20 UTC we got in touch with AWS to discuss whether this was likely.

By 19:10 our discussions with AWS had revealed nothing of interest. The "glitches" had become a noticeable problem for users, and we decided that while there was no obvious sign of hardware problems, it would be good to at least eliminate that as a possible cause, so we took a snapshot of all disks containing user data (for safety), then migrated the server to new hardware, causing a 20-minute outage for users on that file server (who were already seeing a serious slowdown anyway), and a 5-minute outage for everyone else, the latter because we had to reboot the execution servers

After this move, at 19:57 UTC, everything seemed OK. Our monitoring was clear, and the users we were in touch with confirmed that everything was looking good.

21 July: the problem continues

At 14:31 UTC on 21 July, we saw another glitch on our monitoring. Again, the problem cleared up quickly, but we started looking again into what could possibly be the cause. There were further glitches at 15:17 and 16:51, but then the problem seemed to clear up.

Unfortunately at 22:44 it flared up again. Again, the issues started happening more frequently, and lasting longer each time, until they became very noticeable for our users at around 00:30 UTC. At 00:55 UTC we decided to move the server to different hardware again -- there's no official way to force a move to new hardware on AWS; stopping and starting an instance usually does it, but there's a small chance you'd end up on the same physical host again, so a second attempt seemed worth-while. If nothing else, it would hopefully at least clear things up for another 12 hours or so and buy us time to work out what was really going wrong.

This time, things didn't go according to plan. The file server failed to come up on the new hardware, and trying to move again did not help. We decided that we were going to need to provision a completely fresh file server, and move the disks across. While we have processes in place for replacing file servers as part of a normal system update, and for moving them to new hardware without changing (for example) their IP address, replacing one under these circumstances is not a procedure we've done before. Luckily, it went as well as could be expected under the circumstances. At 01:23 UTC we'd worked out what to do and started the new file server. By 01:50 we'd started the migration, and by 02:20 UTC everything was moved over. There were a few remaining glitches, but these were cleared up by 02:45 UTC.

23 July -- more problems -- and a resolution?

We did not expect the fix we'd put in to be a permanent solution -- though we did have a faint hope that perhaps the problem had been caused by some configuration issue on file-2, which might have been remediated by our having provisioned a new server rather than simply moving the old one. This was never a particularly strong hope, however, and when the problems started again at 12:16 UTC we weren't entirely surprised.

We had generated two new hypotheses about the possible cause of these issues by now:

The problem with both of these hypotheses was that only one of our file servers was affected. All file servers had the same number of workers, and all had been upgraded to 16.04.

Still, it was worth a try, we thought. We decided to try changing the number of daemon processes first, as it we believed it would cause minimal downtime; however, we started up a new file server on 14.04 so that it would be ready just in case.

At 14:41 UTC we reduced the number of workers down to eight. We were happy to see that this was picked up across the cluster without any need to reboot anything, so there was no downtime.

Unfortunately, at 15:04, we saw another problem. We decided to spend more time investigating a few ideas that had occurred to us before taking the system down again. At 19:00 we tried increasing the number of NFS processes to 128, but that didn't help. At 19:23 we decided to go ahead with switching over to the 14.04 server we'd prepared earlier. We kicked off some backup snapshots of the user data, just in case there were problems, and at 19:38 we started the migration over.

This completed at 19:46, but required a restart of all of the execution servers in order to pick up the new file server. We started this process immediately, and web servers came back online at 19:48, consoles at 19:50, and scheduled tasks at 19:55.

By 20:00 we were satisfied that everything looked good, and so we went back to monitoring.

Where we are now

Since the update on Saturday, there were no monitoring glitches at all on Sunday, but we did see one potential problem on Monday at 12:03. However this blip was only noticed from one of our web servers (previous issues affected at least three at a time, and sometimes as many as nine), and the problem has not been followed by any subsequent outages in the 4 hours since, which is somewhat reassuring.

We're continuing to monitor closely, and are brainstorming hypotheses to explain what might have happened (or, perhaps still be happening). Of particular interest is the fact that this issue only affected one of our file servers, despite all of them having been upgraded. One possibility we're considering is that the correlation in timing with the upgrade is simply a red herring -- that instead there's some kind of access pattern, some particular pattern of reads/writes to the storage, which only started at around midday on Thursday after the system update. We're planning possible ways to investigate that should the problem occur again.

Either way, whether the problem is solved now or not, we clearly have much more investigation to do. We'll post again when we have more information.

24 Jul 2017 4:44pm GMT

Python Anywhere: Outage report: 20, 21 and 22 July 2017

We had several outages over the last few days. The problem appears to be fixed now, but investigations into the underlying cause are still underway. This post is a summary of what happened, and what we know so far. Once we've got a better understanding of the issue, we'll post more.

It's worth saying at the outset that while the problems related to the way we manage our users' files, those files themselves were always safe. While availability problems are clearly a big issue, we regard data integrity as more important.

20 July: the system update

On Thursday 20 July, at 05:00 UTC, we released a new system update for PythonAnywhere. This was largely an infrastructural update. In particular, we updated our file servers from Ubuntu 14.04 to 16.04, as part of a general upgrade of all servers in our cluster.

File servers are, of course, the servers that manage the files in your PythonAnywhere disk storage. Each server handles the data for a specific set of users, and serves the files up to the other servers in the cluster that need them -- the "execution" servers where your websites, your scheduled tasks, and your consoles run. The files themselves are stored on network-attached storage (and mirrored in realtime to redundant disks on a separate set of backup servers); the file servers simply act as NFS servers and manage a few simple things like disk quotas.

While the system update took a little longer than we'd planned, once everything was up and running, the system looked stable and all monitoring looked good.

20 July: initial problems

At 12:07 UTC our monitoring system showed a very brief issue. From some of our web servers, it appeared that access to one of our file servers, file-2, had very briefly slowed right down -- it was taking more than 30 seconds to list the specific directory that is monitored. The problem cleared up after about 60 seconds. Other file servers were completely unaffected. We did some investigations, but couldn't find anything, so we chalked it up as a glitch and kept an eye out for further problems.

At 14:12 UTC it happened again, and then over the course of the afternoon, the "glitches" became more frequent and started lasting longer. We discovered that the symptom from the file server's side was that all of the NFS daemons -- the processes that together make up an NFS server -- would all become busy; system load would rise from about 1.5 to 64 or so. They were all waiting uninterruptably on what we think was disk I/O (status "D" in top).

The problem only affected file-2 -- other file servers were all fine. Given that every file server had been upgraded to an identical system image, our initial suspicion was that there might be some kind of hardware problem. At 17:20 UTC we got in touch with AWS to discuss whether this was likely.

By 19:10 our discussions with AWS had revealed nothing of interest. The "glitches" had become a noticeable problem for users, and we decided that while there was no obvious sign of hardware problems, it would be good to at least eliminate that as a possible cause, so we took a snapshot of all disks containing user data (for safety), then migrated the server to new hardware, causing a 20-minute outage for users on that file server (who were already seeing a serious slowdown anyway), and a 5-minute outage for everyone else, the latter because we had to reboot the execution servers

After this move, at 19:57 UTC, everything seemed OK. Our monitoring was clear, and the users we were in touch with confirmed that everything was looking good.

21 July: the problem continues

At 14:31 UTC on 21 July, we saw another glitch on our monitoring. Again, the problem cleared up quickly, but we started looking again into what could possibly be the cause. There were further glitches at 15:17 and 16:51, but then the problem seemed to clear up.

Unfortunately at 22:44 it flared up again. Again, the issues started happening more frequently, and lasting longer each time, until they became very noticeable for our users at around 00:30 UTC. At 00:55 UTC we decided to move the server to different hardware again -- there's no official way to force a move to new hardware on AWS; stopping and starting an instance usually does it, but there's a small chance you'd end up on the same physical host again, so a second attempt seemed worth-while. If nothing else, it would hopefully at least clear things up for another 12 hours or so and buy us time to work out what was really going wrong.

This time, things didn't go according to plan. The file server failed to come up on the new hardware, and trying to move again did not help. We decided that we were going to need to provision a completely fresh file server, and move the disks across. While we have processes in place for replacing file servers as part of a normal system update, and for moving them to new hardware without changing (for example) their IP address, replacing one under these circumstances is not a procedure we've done before. Luckily, it went as well as could be expected under the circumstances. At 01:23 UTC we'd worked out what to do and started the new file server. By 01:50 we'd started the migration, and by 02:20 UTC everything was moved over. There were a few remaining glitches, but these were cleared up by 02:45 UTC.

23 July -- more problems -- and a resolution?

We did not expect the fix we'd put in to be a permanent solution -- though we did have a faint hope that perhaps the problem had been caused by some configuration issue on file-2, which might have been remediated by our having provisioned a new server rather than simply moving the old one. This was never a particularly strong hope, however, and when the problems started again at 12:16 UTC we weren't entirely surprised.

We had generated two new hypotheses about the possible cause of these issues by now:

The problem with both of these hypotheses was that only one of our file servers was affected. All file servers had the same number of workers, and all had been upgraded to 16.04.

Still, it was worth a try, we thought. We decided to try changing the number of daemon processes first, as it we believed it would cause minimal downtime; however, we started up a new file server on 14.04 so that it would be ready just in case.

At 14:41 UTC we reduced the number of workers down to eight. We were happy to see that this was picked up across the cluster without any need to reboot anything, so there was no downtime.

Unfortunately, at 15:04, we saw another problem. We decided to spend more time investigating a few ideas that had occurred to us before taking the system down again. At 19:00 we tried increasing the number of NFS processes to 128, but that didn't help. At 19:23 we decided to go ahead with switching over to the 14.04 server we'd prepared earlier. We kicked off some backup snapshots of the user data, just in case there were problems, and at 19:38 we started the migration over.

This completed at 19:46, but required a restart of all of the execution servers in order to pick up the new file server. We started this process immediately, and web servers came back online at 19:48, consoles at 19:50, and scheduled tasks at 19:55.

By 20:00 we were satisfied that everything looked good, and so we went back to monitoring.

Where we are now

Since the update on Saturday, there were no monitoring glitches at all on Sunday, but we did see one potential problem on Monday at 12:03. However this blip was only noticed from one of our web servers (previous issues affected at least three at a time, and sometimes as many as nine), and the problem has not been followed by any subsequent outages in the 4 hours since, which is somewhat reassuring.

We're continuing to monitor closely, and are brainstorming hypotheses to explain what might have happened (or, perhaps still be happening). Of particular interest is the fact that this issue only affected one of our file servers, despite all of them having been upgraded. One possibility we're considering is that the correlation in timing with the upgrade is simply a red herring -- that instead there's some kind of access pattern, some particular pattern of reads/writes to the storage, which only started at around midday on Thursday after the system update. We're planning possible ways to investigate that should the problem occur again.

Either way, whether the problem is solved now or not, we clearly have much more investigation to do. We'll post again when we have more information.

24 Jul 2017 4:44pm GMT

Will Kahn-Greene: Soloists: code review on a solo project

Summary

I work on some projects with other people, but I also spend a lot of time working on projects by myself. When I'm working by myself, I have difficulties with the following:

  1. code review
  2. bouncing ideas off of people
  3. peer programming
  4. long slogs
  5. getting help when I'm stuck
  6. publicizing my work
  7. dealing with loneliness
  8. going on vacation

I started a #soloists group at Mozilla figuring there are a bunch of other Mozillians who are working on solo projects and maybe if we all work alone together, then that might alleviate some of the problems of working solo. We hang out in the #soloists IRC channel on irc.mozilla.org. If you're solo, join us!

I keep thinking about writing a set of blog posts for things we've talked about in the channel and how I do things. Maybe they'll help you.

This one covers code review.

Read more… (10 mins to read)

24 Jul 2017 4:00pm GMT

Will Kahn-Greene: Soloists: code review on a solo project

Summary

I work on some projects with other people, but I also spend a lot of time working on projects by myself. When I'm working by myself, I have difficulties with the following:

  1. code review
  2. bouncing ideas off of people
  3. peer programming
  4. long slogs
  5. getting help when I'm stuck
  6. publicizing my work
  7. dealing with loneliness
  8. going on vacation

I started a #soloists group at Mozilla figuring there are a bunch of other Mozillians who are working on solo projects and maybe if we all work alone together, then that might alleviate some of the problems of working solo. We hang out in the #soloists IRC channel on irc.mozilla.org. If you're solo, join us!

I keep thinking about writing a set of blog posts for things we've talked about in the channel and how I do things. Maybe they'll help you.

This one covers code review.

Read more… (10 mins to read)

24 Jul 2017 4:00pm GMT

Doug Hellmann: hmac — Cryptographic Message Signing and Verification — PyMOTW 3

The HMAC algorithm can be used to verify the integrity of information passed between applications or stored in a potentially vulnerable location. The basic idea is to generate a cryptographic hash of the actual data combined with a shared secret key. The resulting hash can then be used to check the transmitted or stored message … Continue reading hmac - Cryptographic Message Signing and Verification - PyMOTW 3

24 Jul 2017 1:00pm GMT

Doug Hellmann: hmac — Cryptographic Message Signing and Verification — PyMOTW 3

The HMAC algorithm can be used to verify the integrity of information passed between applications or stored in a potentially vulnerable location. The basic idea is to generate a cryptographic hash of the actual data combined with a shared secret key. The resulting hash can then be used to check the transmitted or stored message … Continue reading hmac - Cryptographic Message Signing and Verification - PyMOTW 3

24 Jul 2017 1:00pm GMT

Python Software Foundation: 2017 Bylaw Changes

The PSF has changed its bylaws, following a discussion and vote among the voting members. I'd like to publicly explain those changes.


For each of the changes, I will describe 1.) what the bylaws used to say prior to June 2017 2.) what the new bylaws say and 3.) why the changes were implemented.


Certification of Voting Members
Every member had to acknowledge that they wanted to vote/or not vote every year.
The bylaws now say that the list of voters is based on criteria decided upon by the board.
The previous bylaws pertaining to this topic created too much work for our staff to handle and sometimes it was not done because we did not have the time resources to do it. We can now change the certification to something more manageable for our staff and our members.


Voting in New PSF Fellow Members
We did not have a procedure in place for this in the previous bylaws.
Now the bylaws allow any member to nominate a Fellow. Additionally, it gives the chance for the PSF Board to create a work group for evaluating the nominations.
We lacked a procedure. We had several inquiries and nominations in the past, but did not have a policy to respond with. Now that we voted in this bylaw, the PSF Board voted in the creation of the Work Group. We can now begin accepting new Fellow Members after several years.
Staggered Board Terms
We did not have staggered board terms prior to June 2017. Every director would be voted on every term.
The bylaws now say that in the June election, the top 4 voted directors would hold 3 year terms, the next 4 voted-in directors hold 2 year terms and the next 3 voted-in directors hold 1 year terms. That resulted in:
  1. Naomi Ceder (3 yr)
  2. Eric Holscher (3 yr)
  3. Jackie Kazil (3 yr)
  4. Paul Hildebrandt (3 yr)
  5. Lorena Mesa (2 yr)
  6. Thomas Wouters (2 yr)
  7. Kushal Das (2 yr)
  8. Marlene Mhangami (2 yr)
  9. Kenneth Reitz (1 yr)
  10. Trey Hunner (1 yr)
  11. Paola Katherine Pacheco (1 yr)
The main push behind this change is continuity. As the PSF continues to grow, we are hoping to make it more stable and sustainable. Having some directors in place for more than one year will help us better complete short-term and long-term projects. It will also help us pass on context from previous discussions and meetings.
Direct Officers
We did not have Direct Officers prior to June 2017.
The bylaws state that the current General Counsel and Director of Operations will be the Direct Officers of the PSF. Additionally, they state that the Direct Officers become the 12th and 13th members of the board giving them rights to vote on board business. Direct Officers can be removed by a.) fail of an approval vote, held on at least the same schedule as 3-year-term directors; b) leave the office associated with the officer director position; or c) fail a no-confidence vote.
In an effort to become a more stable and mature board, we are appointing two important positions to be directors of the board. Having the General Counsel and Director of Operations on the board helps us have more strength with legal situations and how the PSF operates. The two new Direct Officers are:
  1. Van Lindberg
  2. Ewa Jodlowska
Delegating Ability to Set Compensation
The bylaws used to state that the President of the Foundation would direct how compensation of the Foundation's employees was decided.
The bylaws have changed so that the Board of Directors decide how employee compensation is decided.
This change was made because even though we keep the president informed of major changes, Guido does not participate in day to day operations nor employee management. We wanted the bylaws to clarify the most effective and fair way we set compensation for our staff.


We hope this breakdown sheds light on the changes and why they were important to implement. Please feel free to contact me with any questions or concerns.

24 Jul 2017 11:35am GMT

Python Software Foundation: 2017 Bylaw Changes

The PSF has changed its bylaws, following a discussion and vote among the voting members. I'd like to publicly explain those changes.


For each of the changes, I will describe 1.) what the bylaws used to say prior to June 2017 2.) what the new bylaws say and 3.) why the changes were implemented.


Certification of Voting Members
Every member had to acknowledge that they wanted to vote/or not vote every year.
The bylaws now say that the list of voters is based on criteria decided upon by the board.
The previous bylaws pertaining to this topic created too much work for our staff to handle and sometimes it was not done because we did not have the time resources to do it. We can now change the certification to something more manageable for our staff and our members.


Voting in New PSF Fellow Members
We did not have a procedure in place for this in the previous bylaws.
Now the bylaws allow any member to nominate a Fellow. Additionally, it gives the chance for the PSF Board to create a work group for evaluating the nominations.
We lacked a procedure. We had several inquiries and nominations in the past, but did not have a policy to respond with. Now that we voted in this bylaw, the PSF Board voted in the creation of the Work Group. We can now begin accepting new Fellow Members after several years.
Staggered Board Terms
We did not have staggered board terms prior to June 2017. Every director would be voted on every term.
The bylaws now say that in the June election, the top 4 voted directors would hold 3 year terms, the next 4 voted-in directors hold 2 year terms and the next 3 voted-in directors hold 1 year terms. That resulted in:
  1. Naomi Ceder (3 yr)
  2. Eric Holscher (3 yr)
  3. Jackie Kazil (3 yr)
  4. Paul Hildebrandt (3 yr)
  5. Lorena Mesa (2 yr)
  6. Thomas Wouters (2 yr)
  7. Kushal Das (2 yr)
  8. Marlene Mhangami (2 yr)
  9. Kenneth Reitz (1 yr)
  10. Trey Hunner (1 yr)
  11. Paola Katherine Pacheco (1 yr)
The main push behind this change is continuity. As the PSF continues to grow, we are hoping to make it more stable and sustainable. Having some directors in place for more than one year will help us better complete short-term and long-term projects. It will also help us pass on context from previous discussions and meetings.
Direct Officers
We did not have Direct Officers prior to June 2017.
The bylaws state that the current General Counsel and Director of Operations will be the Direct Officers of the PSF. Additionally, they state that the Direct Officers become the 12th and 13th members of the board giving them rights to vote on board business. Direct Officers can be removed by a.) fail of an approval vote, held on at least the same schedule as 3-year-term directors; b) leave the office associated with the officer director position; or c) fail a no-confidence vote.
In an effort to become a more stable and mature board, we are appointing two important positions to be directors of the board. Having the General Counsel and Director of Operations on the board helps us have more strength with legal situations and how the PSF operates. The two new Direct Officers are:
  1. Van Lindberg
  2. Ewa Jodlowska
Delegating Ability to Set Compensation
The bylaws used to state that the President of the Foundation would direct how compensation of the Foundation's employees was decided.
The bylaws have changed so that the Board of Directors decide how employee compensation is decided.
This change was made because even though we keep the president informed of major changes, Guido does not participate in day to day operations nor employee management. We wanted the bylaws to clarify the most effective and fair way we set compensation for our staff.


We hope this breakdown sheds light on the changes and why they were important to implement. Please feel free to contact me with any questions or concerns.

24 Jul 2017 11:35am GMT

10 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: King Willams Town Bahnhof

Gestern musste ich morgens zur Station nach KWT um unsere Rerservierten Bustickets für die Weihnachtsferien in Capetown abzuholen. Der Bahnhof selber ist seit Dezember aus kostengründen ohne Zugverbindung - aber Translux und co - die langdistanzbusse haben dort ihre Büros.


Größere Kartenansicht




© benste CC NC SA

10 Nov 2011 10:57am GMT

09 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein

Niemand ist besorgt um so was - mit dem Auto fährt man einfach durch, und in der City - nahe Gnobie- "ne das ist erst gefährlich wenn die Feuerwehr da ist" - 30min später auf dem Rückweg war die Feuerwehr da.




© benste CC NC SA

09 Nov 2011 8:25pm GMT

08 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Brai Party

Brai = Grillabend o.ä.

Die möchte gern Techniker beim Flicken ihrer SpeakOn / Klinke Stecker Verzweigungen...

Die Damen "Mamas" der Siedlung bei der offiziellen Eröffnungsrede

Auch wenn weniger Leute da waren als erwartet, Laute Musik und viele Leute ...

Und natürlich ein Feuer mit echtem Holz zum Grillen.

© benste CC NC SA

08 Nov 2011 2:30pm GMT

07 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Lumanyano Primary

One of our missions was bringing Katja's Linux Server back to her room. While doing that we saw her new decoration.

Björn, Simphiwe carried the PC to Katja's school


© benste CC NC SA

07 Nov 2011 2:00pm GMT

06 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Nelisa Haircut

Today I went with Björn to Needs Camp to Visit Katja's guest family for a special Party. First of all we visited some friends of Nelisa - yeah the one I'm working with in Quigney - Katja's guest fathers sister - who did her a haircut.

African Women usually get their hair done by arranging extensions and not like Europeans just cutting some hair.

In between she looked like this...

And then she was done - looks amazing considering the amount of hair she had last week - doesn't it ?

© benste CC NC SA

06 Nov 2011 7:45pm GMT

05 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Mein Samstag

Irgendwie viel mir heute auf das ich meine Blogposts mal ein bischen umstrukturieren muss - wenn ich immer nur von neuen Plätzen berichte, dann müsste ich ja eine Rundreise machen. Hier also mal ein paar Sachen aus meinem heutigen Alltag.

Erst einmal vorweg, Samstag zählt zumindest für uns Voluntäre zu den freien Tagen.

Dieses Wochenende sind nur Rommel und ich auf der Farm - Katja und Björn sind ja mittlerweile in ihren Einsatzstellen, und meine Mitbewohner Kyle und Jonathan sind zu Hause in Grahamstown - sowie auch Sipho der in Dimbaza wohnt.
Robin, die Frau von Rommel ist in Woodie Cape - schon seit Donnerstag um da ein paar Sachen zur erledigen.
Naja wie dem auch sei heute morgen haben wir uns erstmal ein gemeinsames Weetbix/Müsli Frühstück gegönnt und haben uns dann auf den Weg nach East London gemacht. 2 Sachen waren auf der Checkliste Vodacom, Ethienne (Imobilienmakler) außerdem auf dem Rückweg die fehlenden Dinge nach NeedsCamp bringen.

Nachdem wir gerade auf der Dirtroad losgefahren sind mussten wir feststellen das wir die Sachen für Needscamp und Ethienne nicht eingepackt hatten aber die Pumpe für die Wasserversorgung im Auto hatten.

Also sind wir in EastLondon ersteinmal nach Farmerama - nein nicht das onlinespiel farmville - sondern einen Laden mit ganz vielen Sachen für eine Farm - in Berea einem nördlichen Stadteil gefahren.

In Farmerama haben wir uns dann beraten lassen für einen Schnellverschluss der uns das leben mit der Pumpe leichter machen soll und außerdem eine leichtere Pumpe zur Reperatur gebracht, damit es nicht immer so ein großer Aufwand ist, wenn mal wieder das Wasser ausgegangen ist.

Fego Caffé ist in der Hemmingways Mall, dort mussten wir und PIN und PUK einer unserer Datensimcards geben lassen, da bei der PIN Abfrage leider ein zahlendreher unterlaufen ist. Naja auf jeden Fall speichern die Shops in Südafrika so sensible Daten wie eine PUK - die im Prinzip zugang zu einem gesperrten Phone verschafft.

Im Cafe hat Rommel dann ein paar online Transaktionen mit dem 3G Modem durchgeführt, welches ja jetzt wieder funktionierte - und übrigens mittlerweile in Ubuntu meinem Linuxsystem perfekt klappt.

Nebenbei bin ich nach 8ta gegangen um dort etwas über deren neue Deals zu erfahren, da wir in einigen von Hilltops Centern Internet anbieten wollen. Das Bild zeigt die Abdeckung UMTS in NeedsCamp Katjas Ort. 8ta ist ein neuer Telefonanbieter von Telkom, nachdem Vodafone sich Telkoms anteile an Vodacom gekauft hat müssen die komplett neu aufbauen.
Wir haben uns dazu entschieden mal eine kostenlose Prepaidkarte zu testen zu organisieren, denn wer weis wie genau die Karte oben ist ... Bevor man einen noch so billigen Deal für 24 Monate signed sollte man wissen obs geht.

Danach gings nach Checkers in Vincent, gesucht wurden zwei Hotplates für WoodyCape - R 129.00 eine - also ca. 12€ für eine zweigeteilte Kochplatte.
Wie man sieht im Hintergrund gibts schon Weihnachtsdeko - Anfang November und das in Südafrika bei sonnig warmen min- 25°C

Mittagessen haben wir uns bei einem Pakistanischen Curry Imbiss gegönnt - sehr empfehlenswert !
Naja und nachdem wir dann vor ner Stunde oder so zurück gekommen sind habe ich noch den Kühlschrank geputzt den ich heute morgen zum defrosten einfach nach draußen gestellt hatte. Jetzt ist der auch mal wieder sauber und ohne 3m dicke Eisschicht...

Morgen ... ja darüber werde ich gesondert berichten ... aber vermutlich erst am Montag, denn dann bin ich nochmal wieder in Quigney(East London) und habe kostenloses Internet.

© benste CC NC SA

05 Nov 2011 4:33pm GMT

31 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Sterkspruit Computer Center

Sterkspruit is one of Hilltops Computer Centres in the far north of Eastern Cape. On the trip to J'burg we've used the opportunity to take a look at the centre.

Pupils in the big classroom


The Trainer


School in Countryside


Adult Class in the Afternoon


"Town"


© benste CC NC SA

31 Oct 2011 4:58pm GMT

Benedict Stein: Technical Issues

What are you doing in an internet cafe if your ADSL and Faxline has been discontinued before months end. Well my idea was sitting outside and eating some ice cream.
At least it's sunny and not as rainy as on the weekend.


© benste CC NC SA

31 Oct 2011 3:11pm GMT

30 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Nellis Restaurant

For those who are traveling through Zastron - there is a very nice Restaurant which is serving delicious food at reasanable prices.
In addition they're selling home made juices jams and honey.




interior


home made specialities - the shop in the shop


the Bar


© benste CC NC SA

30 Oct 2011 4:47pm GMT

29 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: The way back from J'burg

Having the 10 - 12h trip from J'burg back to ELS I was able to take a lot of pcitures including these different roadsides

Plain Street


Orange River in its beginngings (near Lesotho)


Zastron Anglican Church


The Bridge in Between "Free State" and Eastern Cape next to Zastron


my new Background ;)


If you listen to GoogleMaps you'll end up traveling 50km of gravel road - as it was just renewed we didn't have that many problems and saved 1h compared to going the official way with all it's constructions sites




Freeway


getting dark


© benste CC NC SA

29 Oct 2011 4:23pm GMT

28 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Wie funktioniert eigentlich eine Baustelle ?

Klar einiges mag anders sein, vieles aber gleich - aber ein in Deutschland täglich übliches Bild einer Straßenbaustelle - wie läuft das eigentlich in Südafrika ?

Ersteinmal vorweg - NEIN keine Ureinwohner die mit den Händen graben - auch wenn hier mehr Manpower genutzt wird - sind sie fleißig mit Technologie am arbeiten.

Eine ganz normale "Bundesstraße"


und wie sie erweitert wird


gaaaanz viele LKWs


denn hier wird eine Seite über einen langen Abschnitt komplett gesperrt, so das eine Ampelschaltung mit hier 45 Minuten Wartezeit entsteht


Aber wenigstens scheinen die ihren Spaß zu haben ;) - Wie auch wir denn gücklicher Weise mussten wir nie länger als 10 min. warten.

© benste CC NC SA

28 Oct 2011 4:20pm GMT