<commit_before>"""
Project-related classes and functions.
"""

from contextlib import contextmanager
import csv
import importlib
import os
import sys
import timeit

import semantic_version

from bldlib import command
from bldlib.command import CommandException
from bldlib import logger

def format_duration(duration):
    """
    Format a duration in second as a hour:minute:second string.
    """
    hours, remainder = divmod(duration, 3600)
    minutes, seconds = divmod(remainder, 60)
    return '%d:%02d:%02d' % (hours, minutes, seconds)

class ProjectException(Exception):
    """
    Project-related exception.
    """
    pass

class ModuleException(Exception):
    """
    Module-related exception.
    """
    pass

def load_project(project_dir):
    """
    Loads the project definition.
    """
    if not project_dir or not os.path.exists(project_dir):
        raise ProjectException("Project directory does not exist")

    sys.path.append(project_dir)
    try:
        project_module = importlib.import_module('projectfile')
    except ImportError as err:
        raise ProjectException(
            "No project definition (projectfile.py) in %s." % project_dir, err)

    if not hasattr(project_module, 'NAME'):
        raise ProjectException("No NAME attribute in project definition")
    if not hasattr(project_module, 'VERSION'):
        raise ProjectException("No VERSION attribute in project definition")
    if not hasattr(project_module, 'MODULES'):
        raise ProjectException("No MODULES attribute in project definition")
    if hasattr(project_module, 'BUILD_DIR'):
        build_dir = os.path.realpath(os.path.join(project_dir, project_module.BUILD_DIR))
    else:
        build_dir = os.path.realpath(os.path.join(project_dir, 'build'))
    if hasattr(project_module, 'CUSTOM_ARGS'):
        custom_args = project_module.CUSTOM_ARGS
    else:
        custom_args = None

    return Project(project_module,
                   project_module.NAME,
                   project_module.VERSION,
                   project_module.MODULES,
                   custom_args,
                   project_dir,
                   build_dir)

class Project:
    """
    The Project class contains all the information about the project.
    """

    def __init__(self, projectfile, name, version, modules, custom_args, root_dir, build_dir):
        self._logger = logger.Logger()
        if not projectfile:
            raise ProjectException("Invalid projectfile")
        self._projectfile = projectfile
        if not name:
            raise ProjectException("Invalid project name")
        self._name = name
        try:
            self._version = semantic_version.Version(version)
        except ValueError:
            raise ProjectException("Invalid version: %s" % version)
        if not isinstance(modules, list):
            raise ProjectException("Modules must be defined as a list")
        if not modules:
            raise ProjectException("At least one module must be defined")<commit_msg>Fix error when custom_args are not defined<commit_after>"""
Project-related classes and functions.
"""

from contextlib import contextmanager
import csv
import importlib
import os
import sys
import timeit

import semantic_version

from bldlib import command
from bldlib.command import CommandException
from bldlib import logger

def format_duration(duration):
    """
    Format a duration in second as a hour:minute:second string.
    """
    hours, remainder = divmod(duration, 3600)
    minutes, seconds = divmod(remainder, 60)
    return '%d:%02d:%02d' % (hours, minutes, seconds)

class ProjectException(Exception):
    """
    Project-related exception.
    """
    pass

class ModuleException(Exception):
    """
    Module-related exception.
    """
    pass

def load_project(project_dir):
    """
    Loads the project definition.
    """
    if not project_dir or not os.path.exists(project_dir):
        raise ProjectException("Project directory does not exist")

    sys.path.append(project_dir)
    try:
        project_module = importlib.import_module('projectfile')
    except ImportError as err:
        raise ProjectException(
            "No project definition (projectfile.py) in %s." % project_dir, err)

    if not hasattr(project_module, 'NAME'):
        raise ProjectException("No NAME attribute in project definition")
    if not hasattr(project_module, 'VERSION'):
        raise ProjectException("No VERSION attribute in project definition")
    if not hasattr(project_module, 'MODULES'):
        raise ProjectException("No MODULES attribute in project definition")
    if hasattr(project_module, 'BUILD_DIR'):
        build_dir = os.path.realpath(os.path.join(project_dir, project_module.BUILD_DIR))
    else:
        build_dir = os.path.realpath(os.path.join(project_dir, 'build'))
    if hasattr(project_module, 'CUSTOM_ARGS'):
        custom_args = project_module.CUSTOM_ARGS
    else:
        custom_args = []

    return Project(project_module,
                   project_module.NAME,
                   project_module.VERSION,
                   project_module.MODULES,
                   custom_args,
                   project_dir,
                   build_dir)

class Project:
    """
    The Project class contains all the information about the project.
    """

    def __init__(self, projectfile, name, version, modules, custom_args, root_dir, build_dir):
        self._logger = logger.Logger()
        if not projectfile:
            raise ProjectException("Invalid projectfile")
        self._projectfile = projectfile
        if not name:
            raise ProjectException("Invalid project name")
        self._name = name
        try:
            self._version = semantic_version.Version(version)
        except ValueError:
            raise ProjectException("Invalid version: %s" % version)
        if not isinstance(modules, list):
            raise ProjectException("Modules must be defined as a list")
        if not modules:
            raise ProjectException("At least one module must be defined")
{'fraction_non_alphanumeric': 0.08439096752925664, 'fraction_numerical': 0.0032965221691115872, 'mean_word_length': 2.828391167192429, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '63069', 'n_tokens_mistral': 1607, 'n_tokens_neox': 1574, 'n_words': 474}