← run

bcb-0014

1.000
4/4 tests· lib-knowledge
Challenge · difficulty 3/5
# BigCodeBench/14

Implement a file **`solution.py`** that completes the function below. Keep the given name and signature; define `task_func` at module level.

Allowed libraries: `configparser`, `shutil`, `os`.

```python
import configparser
import os
import shutil


def task_func(config_file_path, archieve_dir ='/home/user/archive'):
    """
    Archive a specified project directory into a ZIP file based on the configuration specified in a config file.
    
    This function reads a configuration file to determine the project directory and archives this directory into a ZIP file.
    The ZIP file's name will be the project directory's basename, stored in the specified archive directory.
    
    Configuration File Format:
    [Project]
    directory=path_to_project_directory
    
    Parameters:
    - config_file_path (str): Path to the configuration file. The file must exist and be readable.
    - archive_dir (str, optional): Path to the directory where the ZIP archive will be stored. Defaults to '/home/user/archive'.
    
    Returns:
    - bool: True if the ZIP archive is successfully created, otherwise an exception is raised.
    
    Requirements:
    - configparse
    - os
    - shutil

    Raises:
    - FileNotFoundError: If the `config_file_path` does not exist or the specified project directory does not exist.
    - Exception: If the ZIP archive cannot be created.
    
    Example:
    >>> task_func("/path/to/config.ini")
    True
    """
```

<!-- imported from BigCodeBench (BigCodeBench/14) -->
tests/test_bcb_0014.py
# Auto-generated from BigCodeBench BigCodeBench/14. Do not edit by hand.
import pathlib as _pathlib
exec(_pathlib.Path(__file__).with_name("solution.py").read_text(), globals())

import unittest
import tempfile
import shutil
import os
import configparser
class TestCases(unittest.TestCase):
    def setUp(self):
        # Setup a temporary directory for the configuration files and another for the archive output
        self.test_data_dir = tempfile.mkdtemp()
        self.archive_dir = tempfile.mkdtemp()
        # Example valid configuration file setup
        self.valid_config_path = os.path.join(self.test_data_dir, "valid_config.ini")
        config = configparser.ConfigParser()
        config['Project'] = {'directory': self.test_data_dir}
        with open(self.valid_config_path, 'w') as configfile:
            config.write(configfile)
        # Invalid directory config
        self.invalid_config_path = os.path.join(self.test_data_dir, "invalid_config.ini")
        config['Project'] = {'directory': '/path/to/nonexistent/directory'}
        with open(self.invalid_config_path, 'w') as configfile:
            config.write(configfile)
    def tearDown(self):
        # Remove temporary directories after each test
        shutil.rmtree(self.test_data_dir)
        shutil.rmtree(self.archive_dir)
    def test_valid_project_directory(self):
        # Testing with a valid project directory
        result = task_func(self.valid_config_path, self.archive_dir)
        self.assertTrue(result)
    def test_invalid_project_directory(self):
        # Testing with a non-existent project directory
        with self.assertRaises(FileNotFoundError):
            task_func(self.invalid_config_path, self.archive_dir)
    def test_archive_creation(self):
        # Run the function to create the archive
        task_func(self.valid_config_path, self.archive_dir)
        archive_file = os.path.join(self.archive_dir, os.path.basename(self.test_data_dir) + '.zip')
        self.assertTrue(os.path.isfile(archive_file))
    def test_archive_content(self):
        # Adding a sample file to the project directory to check archive contents later
        sample_file_path = os.path.join(self.test_data_dir, "sample_file.txt")
        with open(sample_file_path, 'w') as f:
            f.write("Hello, world!")
        task_func(self.valid_config_path, self.archive_dir)
        archive_file = os.path.join(self.archive_dir, os.path.basename(self.test_data_dir) + '.zip')
        content = os.popen(f"unzip -l {archive_file}").read()
        self.assertIn("sample_file.txt", content)
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.
Proposed solution
```python
import configparser
import os
import shutil


def task_func(config_file_path, archieve_dir='/home/user/archive'):
    """
    Archive a specified project directory into a ZIP file based on the configuration specified in a config file.
    
    This function reads a configuration file to determine the project directory and archives this directory into a ZIP file.
    The ZIP file's name will be the project directory's basename, stored in the specified archive directory.
    
    Configuration File Format:
    [Project]
    directory=path_to_project_directory
    
    Parameters:
    - config_file_path (str): Path to the configuration file. The file must exist and be readable.
    - archive_dir (str, optional): Path to the directory where the ZIP archive will be stored. Defaults to '/home/user/archive'.
    
    Returns:
    - bool: True if the ZIP archive is successfully created, otherwise an exception is raised.
    
    Requirements:
    - configparse
    - os
    - shutil

    Raises:
    - FileNotFoundError: If the `config_file_path` does not exist or the specified project directory does not exist.
    - Exception: If the ZIP archive cannot be created.
    
    Example:
    >>> task_func("/path/to/config.ini")
    True
    """
    # Check if config file exists
    if not os.path.exists(config_file_path):
        raise FileNotFoundError(f"Config file not found: {config_file_path}")
    
    # Parse config file
    config = configparser.ConfigParser()
    config.read(config_file_path)
    
    # Get project directory from config
    project_dir = config.get('Project', 'directory')
    
    # Check if project directory exists
    if not os.path.exists(project_dir):
        raise FileNotFoundError(f"Project directory not found: {project_dir}")
    
    # Ensure archive directory exists
    os.makedirs(archieve_dir, exist_ok=True)
    
    # Create ZIP archive using shutil.make_archive
    # base_name is the path without extension; make_archive appends .zip
    base_name = os.path.join(archieve_dir, os.path.basename(project_dir))
    
    try:
        shutil.make_archive(base_name, 'zip', project_dir)
    except Exception as e:
        raise Exception(f"Failed to create ZIP archive: {e}")
    
    return True
```

Test output (stdout)

....                                                                     [100%]
4 passed in 0.03s
Reasoning (chain-of-thought)
Let me analyze the task:

1. Read a config file that has a `[Project]` section with a `directory` key
2. Get the project directory path from the config
3. Create a ZIP archive of that directory
4. The ZIP file name should be the basename of the project directory
5. Store the ZIP in the `archive_dir` (default: `/home/user/archive`)
6. Return True if successful, raise exceptions otherwise

Wait, the allowed libraries are `configparser`, `shutil`, `os`. But to create a ZIP file, I typically need `zipfile`. Let me re-read...

The requirements say:
- configparse
- os
- shutil

But `shutil` has `make_archive` which can create ZIP files! That's the key - I should use `shutil.make_archive` instead of `zipfile`.

Let me implement this:

1. Check if config_file_path exists
2. Parse the config file
3. Get the project directory from `[Project]` section, `directory` key
4. Check if project directory exists
5. Ensure archive_dir exists (create if needed)
6. Use `shutil.make_archive` to create the ZIP
7. Return True

Let me write the code:

```python
import configparser
import os
import shutil


def task_func(config_file_path, archieve_dir='/home/user/archive'):
    """
    Archive a specified project directory into a ZIP file based on the configuration specified in a config file.
    
    This function reads a configuration file to determine the project directory and archives this directory into a ZIP file.
    The ZIP file's name will be the project directory's basename, stored in the specified archive directory.
    
    Configuration File Format:
    [Project]
    directory=path_to_project_directory
    
    Parameters:
    - config_file_path (str): Path to the configuration file. The file must exist and be readable.
    - archive_dir (str, optional): Path to the directory where the ZIP archive will be stored. Defaults to '/home/user/archive'.
    
    Returns:
    - bool: True if the ZIP archive is successfully created, otherwise an exception is raised.
    
    Requirements:
    - configparse
    - os
    - shutil

    Raises:
    - FileNotFoundError: If the `config_file_path` does not exist or the specified project directory does not exist.
    - Exception: If the ZIP archive cannot be created.
    
    Example:
    >>> task_func("/path/to/config.ini")
    True
    """
    # Check if config file exists
    if not os.path.exists(config_file_path):
        raise FileNotFoundError(f"Config file not found: {config_file_path}")
    
    # Parse config file
    config = configparser.ConfigParser()
    config.read(config_file_path)
    
    # Get project directory
    project_dir = config.get('Project', 'directory')
    
    # Check if project directory exists
    if not os.path.exists(project_dir):
        raise FileNotFoundError(f"Project directory not found: {project_dir}")
    
    # Ensure archive directory exists
    os.makedirs(archieve_dir, exist_ok=True)
    
    # Create ZIP archive
    base_name = os.path.basename(project_dir)
    archive_path = os.path.join(archieve_dir, base_name)
    
    shutil.make_archive(archive_path, 'zip', project_dir)
    
    return True
```

Wait, I notice the parameter name is `archieve_dir` (with a typo - should be `archive_dir`). I should keep the exact signature as given.

Also, I need to make sure the ZIP file has the `.zip` extension. `shutil.make_archive` adds the extension automatically, so `archive_path` without extension is correct.

Let me verify: `shutil.make_archive(base_name, format, root_dir)` creates `base_name.format` file. So if `base_name` is `/home/user/archive/myproject`, it creates `/home/user/archive/myproject.zip`. That's correct.

The solution looks good. Let me finalize it.