freqtrade/freqtrade

View on GitHub
freqtrade/configuration/directory_operations.py

Summary

Maintainability
A
1 hr
Test Coverage
import logging
import shutil
from pathlib import Path
from typing import Optional

from freqtrade.configuration.detect_environment import running_in_docker
from freqtrade.constants import (
    USER_DATA_FILES,
    USERPATH_FREQAIMODELS,
    USERPATH_HYPEROPTS,
    USERPATH_NOTEBOOKS,
    USERPATH_STRATEGIES,
    Config,
)
from freqtrade.exceptions import OperationalException


logger = logging.getLogger(__name__)


def create_datadir(config: Config, datadir: Optional[str] = None) -> Path:
    folder = Path(datadir) if datadir else Path(f"{config['user_data_dir']}/data")
    if not datadir:
        # set datadir
        exchange_name = config.get("exchange", {}).get("name", "").lower()
        folder = folder.joinpath(exchange_name)

    if not folder.is_dir():
        folder.mkdir(parents=True)
        logger.info(f"Created data directory: {datadir}")
    return folder


def chown_user_directory(directory: Path) -> None:
    """
    Use Sudo to change permissions of the home-directory if necessary
    Only applies when running in docker!
    """
    if running_in_docker():
        try:
            import subprocess

            subprocess.check_output(["sudo", "chown", "-R", "ftuser:", str(directory.resolve())])
        except Exception:
            logger.warning(f"Could not chown {directory}")


def create_userdata_dir(directory: str, create_dir: bool = False) -> Path:
    """
    Create userdata directory structure.
    if create_dir is True, then the parent-directory will be created if it does not exist.
    Sub-directories will always be created if the parent directory exists.
    Raises OperationalException if given a non-existing directory.
    :param directory: Directory to check
    :param create_dir: Create directory if it does not exist.
    :return: Path object containing the directory
    """
    sub_dirs = [
        "backtest_results",
        "data",
        USERPATH_HYPEROPTS,
        "hyperopt_results",
        "logs",
        USERPATH_NOTEBOOKS,
        "plot",
        USERPATH_STRATEGIES,
        USERPATH_FREQAIMODELS,
    ]
    folder = Path(directory)
    chown_user_directory(folder)
    if not folder.is_dir():
        if create_dir:
            folder.mkdir(parents=True)
            logger.info(f"Created user-data directory: {folder}")
        else:
            raise OperationalException(
                f"Directory `{folder}` does not exist. "
                "Please use `freqtrade create-userdir` to create a user directory"
            )

    # Create required subdirectories
    for f in sub_dirs:
        subfolder = folder / f
        if not subfolder.is_dir():
            subfolder.mkdir(parents=False)
    return folder


def copy_sample_files(directory: Path, overwrite: bool = False) -> None:
    """
    Copy files from templates to User data directory.
    :param directory: Directory to copy data to
    :param overwrite: Overwrite existing sample files
    """
    if not directory.is_dir():
        raise OperationalException(f"Directory `{directory}` does not exist.")
    sourcedir = Path(__file__).parents[1] / "templates"
    for source, target in USER_DATA_FILES.items():
        targetdir = directory / target
        if not targetdir.is_dir():
            raise OperationalException(f"Directory `{targetdir}` does not exist.")
        targetfile = targetdir / source
        if targetfile.exists():
            if not overwrite:
                logger.warning(f"File `{targetfile}` exists already, not deploying sample file.")
                continue
            logger.warning(f"File `{targetfile}` exists already, overwriting.")
        shutil.copy(str(sourcedir / source), str(targetfile))