Is there an easy way to get all common module extensions?
Question: I am making a library that deals with Python modules. Without getting into
details, I need a list of the common Python module extensions.

Obviously, I want `.py`, but I'd also like to include ones such as `.pyw`,
`.pyd`, etc. In other words, I want anything that you can import.

Is there a tool in the standard library which will make this list for me? Or
do I have to make it myself (and hardcode all of the values)?

    
    
    extensions = ['.py', '.pyw', ...]
    


Answer: This functionality can be found in the [`importlib.machinery`
module](https://docs.python.org/3/library/importlib.html#module-
importlib.machinery). Inside, there are numerous constants which relate to the
various Python module extensions:

    
    
    >>> import importlib
    >>> importlib.machinery.SOURCE_SUFFIXES
    ['.py', '.pyw']
    >>> importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES
    ['.pyo']
    >>> importlib.machinery.EXTENSION_SUFFIXES
    ['.pyd']
    >>> importlib.machinery.DEBUG_BYTECODE_SUFFIXES
    ['.pyc']
    >>>
    

So, you could very easily join these into a global set1:

    
    
    >>> set(importlib.machinery.SOURCE_SUFFIXES +
    ...     importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES +
    ...     importlib.machinery.EXTENSION_SUFFIXES +
    ...     importlib.machinery.DEBUG_BYTECODE_SUFFIXES)
    {'.pyw', '.py', '.pyd', '.pyc', '.pyo'}
    >>>
    

* * *

You might also be interested in the [`all_suffixes`
function](https://docs.python.org/3/library/importlib.html#importlib.machinery.all_suffixes):

    
    
    >>> importlib.machinery.all_suffixes()
    ['.py', '.pyw', '.pyc', '.pyd']
    >>>
    

Note however that this function will replace `.pyc` with `.pyo` if Python is
launched with either the [`-O` or `-OO`
options](https://docs.python.org/3/using/cmdline.html#miscellaneous-options).
To avoid this, you can do:

    
    
    >>> set(importlib.machinery.all_suffixes() +
    ...     importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES +
    ...     importlib.machinery.DEBUG_BYTECODE_SUFFIXES)
    {'.pyw', '.py', '.pyd', '.pyc', '.pyo'}
    >>>
    

This will ensure that both `.pyc` and `.pyo` are in the set.

* * *

Finally, you should be wary of `importlib.machinery.BYTECODE_SUFFIXES`. As
@MartijnPieters noted in the comments, it will always be equal to either
`OPTIMIZED_BYTECODE_SUFFIXES` or `DEBUG_BYTECODE_SUFFIXES`. This means that if
you add it to the collection, you will get either a duplicated `.pyc` or a
duplicated `.pyo` value (unless you use a set of course).

From the
[docs](https://docs.python.org/3/library/importlib.html#importlib.machinery.BYTECODE_SUFFIXES):

> `importlib.machinery.BYTECODE_SUFFIXES`
>
> A list of strings representing the recognized file suffixes for bytecode
> modules. Set to either `DEBUG_BYTECODE_SUFFIXES` or
> `OPTIMIZED_BYTECODE_SUFFIXES` based on whether `__debug__` is true.

I didn't bother using this constant however because I want both
`OPTIMIZED_BYTECODE_SUFFIXES` and `DEBUG_BYTECODE_SUFFIXES` in the collection.
So, there is no reason to add it.

* * *

1I decided to use a set because they have a faster lookup time than lists.
Meaning, they are better suited for a global collection of values that will
not change and which needs no particular order. In addition, they will ensure
that we do not accidentally add duplicate extensions to the collection.

