Pythonパッケージに追加のファイルを含める方法

PythonPythonBeginner
今すぐ練習

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

Introduction

Python packages are a powerful way to organize and distribute code. While Python scripts (.py files) form the core of a package, you often need to include additional files such as configuration files, data files, templates, or documentation. This tutorial will guide you through the process of creating a Python package that includes these additional resources, making your package more versatile and useful.

By the end of this lab, you will have created a complete Python package with additional files and learned how to access these files from your code.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python(("Python")) -.-> python/FileHandlingGroup(["File Handling"]) python/ModulesandPackagesGroup -.-> python/importing_modules("Importing Modules") python/ModulesandPackagesGroup -.-> python/creating_modules("Creating Modules") python/ModulesandPackagesGroup -.-> python/using_packages("Using Packages") python/FileHandlingGroup -.-> python/file_reading_writing("Reading and Writing Files") python/FileHandlingGroup -.-> python/file_operations("File Operations") subgraph Lab Skills python/importing_modules -.-> lab-398030{{"Pythonパッケージに追加のファイルを含める方法"}} python/creating_modules -.-> lab-398030{{"Pythonパッケージに追加のファイルを含める方法"}} python/using_packages -.-> lab-398030{{"Pythonパッケージに追加のファイルを含める方法"}} python/file_reading_writing -.-> lab-398030{{"Pythonパッケージに追加のファイルを含める方法"}} python/file_operations -.-> lab-398030{{"Pythonパッケージに追加のファイルを含める方法"}} end

Creating a Basic Python Package Structure

Let's start by creating a basic Python package structure. A package is essentially a directory containing Python modules and a special __init__.py file that tells Python this directory should be treated as a package.

Create the Package Directory Structure

First, let's create the necessary directories for our package:

mkdir -p ~/project/mypackage/data

This command creates a directory called mypackage with a subdirectory data to store our additional files.

Now, let's navigate to our project directory:

cd ~/project

Create the Basic Package Files

Every Python package needs an __init__.py file in its root directory. Let's create this file:

touch mypackage/__init__.py

This empty file tells Python that the mypackage directory is a package.

Next, let's create a simple Python module within our package:

echo 'def greet():
    print("Hello from mypackage!")' > mypackage/greeting.py

Add a Data File to the Package

Now, let's add a data file to our package. This could be a configuration file, a CSV file, or any other type of file your package needs:

echo 'This is sample data for our package.' > mypackage/data/sample.txt

Let's also create a configuration file:

echo '[config]
debug = true
log_level = INFO' > mypackage/config.ini

Verify Your Package Structure

You can check the structure of your package with the following command:

find mypackage -type f | sort

You should see output similar to:

mypackage/__init__.py
mypackage/config.ini
mypackage/data/sample.txt
mypackage/greeting.py

This is a basic Python package structure with some additional non-Python files. In the next steps, we'll learn how to include these files when distributing the package and how to access them from your code.

Creating a Setup Script for Your Package

To properly include additional files in your Python package, you need to create a setup.py file. This file is used by Python's packaging tools to build and install your package.

Understanding setup.py

The setup.py file contains metadata about your package, such as its name, version, author, and dependencies. It also specifies which files should be included when the package is distributed.

Let's create a basic setup.py file in the root directory of your project:

cd ~/project

Now, create the setup.py file with the following content:

cat > setup.py << 'EOF'
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="0.1",
    packages=find_packages(),
    
    ## Include data files
    package_data={
        "mypackage": ["config.ini", "data/*.txt"],
    },
    
    ## Metadata
    author="Your Name",
    author_email="[email protected]",
    description="A simple Python package with additional files",
)
EOF

Understanding the Package Data Configuration

The package_data parameter is key to including additional files in your package. It takes a dictionary where:

  • Keys are package names (or "" for all packages)
  • Values are lists of file patterns relative to the package directory

In our example, we're including:

  • The config.ini file at the root of our package
  • All .txt files in the data directory

The file patterns support wildcards like * to match multiple files with similar names or extensions.

Testing Your Setup Configuration

Let's create a virtual environment to test our package:

python3 -m venv ~/project/venv
source ~/project/venv/bin/activate

Now, let's install our package in development mode:

cd ~/project
pip install -e .

The -e flag stands for "editable" mode, which means you can edit your package code without having to reinstall it each time.

You should see output indicating that your package was successfully installed:

Successfully installed mypackage-0.1

Let's verify our package installation:

python -c "import mypackage.greeting; mypackage.greeting.greet()"

This should output:

Hello from mypackage!

You've now successfully created a Python package with a setup script that includes additional files. In the next step, we'll learn how to access these files from your Python code.

Accessing Additional Files in Your Package

Now that we've included additional files in our package, we need to learn how to access them from our Python code. There are several ways to do this, but the most reliable method is to use the pkg_resources module from the setuptools package.

Creating a Module to Access Additional Files

Let's create a new module in our package that demonstrates how to access the additional files:

cd ~/project

Create a new file called fileaccess.py in the mypackage directory:

cat > mypackage/fileaccess.py << 'EOF'
import os
import pkg_resources

def get_config_path():
    """Return the path to the config.ini file."""
    return pkg_resources.resource_filename('mypackage', 'config.ini')

def read_config():
    """Read and return the content of the config.ini file."""
    config_path = get_config_path()
    with open(config_path, 'r') as f:
        return f.read()

def get_sample_data_path():
    """Return the path to the sample.txt file."""
    return pkg_resources.resource_filename('mypackage', 'data/sample.txt')

def read_sample_data():
    """Read and return the content of the sample.txt file."""
    data_path = get_sample_data_path()
    with open(data_path, 'r') as f:
        return f.read()

def list_package_data():
    """List all files included in the package data."""
    ## Get the package directory
    package_dir = os.path.dirname(pkg_resources.resource_filename('mypackage', '__init__.py'))
    
    ## List files in the main package directory
    main_files = [f for f in os.listdir(package_dir) 
                  if os.path.isfile(os.path.join(package_dir, f))]
    
    ## List files in the data directory
    data_dir = os.path.join(package_dir, 'data')
    data_files = [f'data/{f}' for f in os.listdir(data_dir) 
                 if os.path.isfile(os.path.join(data_dir, f))]
    
    return main_files + data_files
EOF

Update the init.py File

Let's update the __init__.py file to expose our new functions:

cat > mypackage/__init__.py << 'EOF'
from mypackage.greeting import greet
from mypackage.fileaccess import (
    get_config_path,
    read_config,
    get_sample_data_path,
    read_sample_data,
    list_package_data
)

__all__ = [
    'greet',
    'get_config_path',
    'read_config',
    'get_sample_data_path',
    'read_sample_data',
    'list_package_data'
]
EOF

Testing the File Access Functions

Let's create a script to test our file access functions:

cat > ~/project/test_package.py << 'EOF'
import mypackage

## Test greeting function
print("Testing greeting function:")
mypackage.greet()
print()

## Test config file access
print("Config file path:")
print(mypackage.get_config_path())
print("\nConfig file content:")
print(mypackage.read_config())
print()

## Test data file access
print("Sample data file path:")
print(mypackage.get_sample_data_path())
print("\nSample data file content:")
print(mypackage.read_sample_data())
print()

## List all package data
print("All package data files:")
for file in mypackage.list_package_data():
    print(f"- {file}")
EOF

Now run the test script:

cd ~/project
python test_package.py

You should see output similar to:

Testing greeting function:
Hello from mypackage!

Config file path:
/home/labex/project/mypackage/config.ini

Config file content:
[config]
debug = true
log_level = INFO

Sample data file path:
/home/labex/project/mypackage/data/sample.txt

Sample data file content:
This is sample data for our package.

All package data files:
- __init__.py
- config.ini
- fileaccess.py
- greeting.py
- data/sample.txt

Understanding pkg_resources

The pkg_resources module provides a way to access resources inside installed packages. The resource_filename function returns the path to a file within a package, regardless of where the package is installed.

This approach ensures that your code can access additional files whether:

  • Running from the source directory during development
  • Installed in a virtual environment
  • Installed system-wide
  • Distributed and installed on a different machine

This makes your package more portable and reliable, as it doesn't rely on hard-coded paths or relative paths that might change depending on how the package is used.

Building and Distributing Your Package

Now that we have created a Python package with additional files and confirmed that we can access them, let's learn how to build and distribute this package.

Updating the Setup Script

Before building the package, let's update our setup.py file to include more metadata and requirements:

cd ~/project
cat > setup.py << 'EOF'
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="0.1.0",
    packages=find_packages(),
    
    ## Include data files
    package_data={
        "mypackage": ["config.ini", "data/*.txt"],
    },
    
    ## Dependencies
    install_requires=[
        "setuptools",
    ],
    
    ## Metadata
    author="Your Name",
    author_email="[email protected]",
    description="A simple Python package with additional files",
    keywords="sample, package, data",
    url="https://example.com/mypackage",
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
    ],
    python_requires=">=3.6",
)
EOF

Building Source and Wheel Distributions

Python packages can be distributed in several formats, but the most common are:

  1. Source Distribution (sdist): A tarball containing the source code and additional files
  2. Wheel Distribution (bdist_wheel): A pre-built package that can be installed without building

Let's create both types of distributions:

## Make sure we have the latest build tools
pip install --upgrade setuptools wheel

## Build the distributions
python setup.py sdist bdist_wheel

You should see output indicating that the distributions were created, and new files should appear in the dist directory.

Let's check the contents of the dist directory:

ls -l dist

You should see at least two files:

  • A .tar.gz file (the source distribution)
  • A .whl file (the wheel distribution)

Installing the Package from the Distribution Files

Now, let's test installing the package from one of the distribution files. First, let's uninstall our development version:

pip uninstall -y mypackage

Now, let's install the wheel distribution:

pip install dist/mypackage-0.1.0-py3-none-any.whl

You should see output indicating that the package was successfully installed.

Let's verify that the package is installed and that we can still access the additional files:

python -c "import mypackage; print(mypackage.read_config())"

This should output the content of the config.ini file:

[config]
debug = true
log_level = INFO

Publishing Your Package

In a real-world scenario, you would typically publish your package to the Python Package Index (PyPI) so that others can install it using pip install mypackage. This would involve:

  1. Creating an account on PyPI (https://pypi.org/)
  2. Using tools like twine to upload your distributions:
    pip install twine
    twine upload dist/*

However, for this lab, we will stop at creating the distributions locally. You now have a complete Python package with additional files that can be distributed and installed by others.

Summary of What You've Created

  • A Python package with modules and additional files
  • A setup script that includes these files in the distribution
  • Functions to access these files from your code
  • Source and wheel distribution files ready for distribution

This structure provides a solid foundation for any Python package you might want to create in the future.

Summary

In this lab, you have learned how to:

  1. Create a basic Python package structure with additional non-Python files
  2. Configure your setup.py to include these files in the package distribution
  3. Access additional files from your Python code using the pkg_resources module
  4. Build source and wheel distributions of your package for distribution

You now have the knowledge to create more comprehensive Python packages that include not just Python code, but also configuration files, data files, templates, and other resources. This capability is essential for developing real-world applications where Python code often needs to work with external files.

Some key takeaways from this lab:

  • Use the package_data parameter in setup() to include additional files
  • Use pkg_resources.resource_filename() to reliably access these files from your code
  • Build both source and wheel distributions for maximum compatibility
  • Keep your package structure organized to make maintenance easier

This knowledge will be valuable as you continue to develop more complex Python applications and packages.