<commit_before>import os
import shutil
import tempfile
import unittest
from contextlib import contextmanager

import pytest
from mock import patch

from pyproj import CRS
from pyproj.datadir import DataDirError, append_data_dir, get_data_dir, set_data_dir


def unset_data_dir():
    from pyproj.datadir import _USER_PROJ_DATA

    _USER_PROJ_DATA = None  # noqa


def create_projdb(tmpdir):
    with open(os.path.join(tmpdir, "proj.db"), "w") as pjdb:
        pjdb.write("DUMMY proj.db")


@contextmanager
def proj_env():
    """
    Ensure environment variable the same at the end of the test.
    """
    proj_lib = os.environ.get("PROJ_LIB")
    try:
        yield
    finally:
        if proj_lib is not None:
            # add it back if it used to be there
            os.environ["PROJ_LIB"] = proj_lib
        else:
            # remove it if it wasn't there previously
            os.environ.pop("PROJ_LIB", None)
        # make sure the data dir is cleared
        set_data_dir(None)


@contextmanager
def temporary_directory():
    """
    Get a temporary directory
    """
    temp_dir = tempfile.mkdtemp()
    try:
        yield temp_dir
    finally:
        shutil.rmtree(temp_dir)


@unittest.skipIf(os.name == "nt", reason="Cannot modify Windows environment variables.")
def test_get_data_dir__missing():
    with proj_env(), pytest.raises(DataDirError), patch(
        "pyproj.datadir.os.path.abspath", return_value="INVALID"
    ), patch("pyproj.datadir.find_executable", return_value=None):
        unset_data_dir()
        os.environ.pop("PROJ_LIB", None)
        assert get_data_dir() is None


def test_get_data_dir__from_user():
    with proj_env(), temporary_directory() as tmpdir, temporary_directory() as tmpdir_env:  # noqa: E501
        create_projdb(tmpdir)
        os.environ["PROJ_LIB"] = tmpdir_env
        create_projdb(tmpdir_env)
        set_data_dir(tmpdir)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        with patch("pyproj.datadir.os.path.abspath") as abspath_mock:
            abspath_mock.return_value = os.path.join(tmpdir, "randomfilename.py")
            assert get_data_dir() == tmpdir


def test_get_data_dir__internal():
    with proj_env(), temporary_directory() as tmpdir:
        unset_data_dir()
        os.environ["PROJ_LIB"] = tmpdir
        create_projdb(tmpdir)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        with patch("pyproj.datadir.os.path.abspath") as abspath_mock:
            abspath_mock.return_value = os.path.join(tmpdir, "randomfilename.py")
            assert get_data_dir() == internal_proj_dir


@unittest.skipIf(os.name == "nt", reason="Cannot modify Windows environment variables.")
def test_get_data_dir__from_env_var():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os.path.abspath", return_value="INVALID"
    ):
        unset_data_dir()
        os.environ["PROJ_LIB"] = tmpdir
        create_projdb(tmpdir)
        assert get_data_dir() == tmpdir


@unittest.skipIf(os.name == "nt", reason="Cannot modify Windows environment variables.")
def test_get_data_dir__from_env_var__multiple():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os.path.abspath", return_value="INVALID"
    ):
        unset_data_dir()
        os.environ["PROJ_LIB"] = os.pathsep.join([tmpdir, tmpdir, tmpdir])
        create_projdb(tmpdir)
        assert get_data_dir() == os.pathsep.join([tmpdir, tmpdir, tmpdir])


@unittest.skipIf(os.name == "nt", reason="Cannot modify Windows environment variables.")
def test_get_data_dir__from_prefix():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os.path.abspath", return_value="INVALID"
    ), patch("pyproj.datadir.sys") as sys_mock:
        unset_data_dir()
        os.environ.pop("PROJ_LIB", None)
        sys_mock.prefix = tmpdir
        proj_dir = os.path.join(tmpdir, "share", "proj")
        os.makedirs(proj_dir)
        create_projdb(proj_dir)
        assert get_data_dir() == proj_dir


@unittest.skipIf(os.name == "nt", reason="Cannot modify Windows environment variables.")
def test_get_data_dir__from_path():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os.path.abspath", return_value="INVALID"
    ), patch("pyproj.datadir.find_executable") as find_exe:
        unset_data_dir()
        os.environ.pop("PROJ_LIB", None)
        find_exe.return_value = os.path.join(tmpdir, "bin", "proj")
        proj_dir = os.path.join(tmpdir, "share", "proj")
        os.makedirs(proj_dir)
        create_projdb(proj_dir)
        assert get_data_dir() == proj_dir


def test_append_data_dir__internal():
    with proj_env(), temporary_directory() as tmpdir:
        unset_data_dir()
        os.environ["PROJ_LIB"] = tmpdir
        create_projdb(tmpdir)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        extra_datadir = str(os.path.join(tmpdir, "extra_datumgrids"))
        with patch("pyproj.datadir.os.path.abspath") as abspath_mock:
            abspath_mock.return_value = os.path.join(tmpdir, "randomfilename.py")
            append_data_dir(extra_datadir)
            assert get_data_dir() == os.pathsep.join([internal_proj_dir, extra_datadir])


def test_creating_multiple_crs_without_file_limit():
    assert [CRS.from_epsg(4326) for _ in range(1200)]<commit_msg>use mock for changing os.environ and sys.prefix in data directory tests (#404)<commit_after>import os
import shutil
import tempfile
import unittest
from contextlib import contextmanager

import pytest
from mock import patch

from pyproj import CRS
from pyproj.datadir import DataDirError, append_data_dir, get_data_dir, set_data_dir


def unset_data_dir():
    from pyproj.datadir import _USER_PROJ_DATA

    _USER_PROJ_DATA = None  # noqa


def create_projdb(tmpdir):
    with open(os.path.join(tmpdir, "proj.db"), "w") as pjdb:
        pjdb.write("DUMMY proj.db")


@contextmanager
def proj_env():
    """
    Ensure environment variable the same at the end of the test.
    """
    try:
        yield
    finally:
        # make sure the data dir is cleared
        set_data_dir(None)


@contextmanager
def temporary_directory():
    """
    Get a temporary directory
    """
    temp_dir = tempfile.mkdtemp()
    try:
        yield temp_dir
    finally:
        shutil.rmtree(temp_dir)


_INVALID_PATH = "/invalid/path/to/nowhere"


def setup_os_mock(os_mock, abspath_return=_INVALID_PATH, proj_dir=None):
    os_mock.path.abspath.return_value = abspath_return
    os_mock.path.join = os.path.join
    os_mock.path.dirname = os.path.dirname
    os_mock.path.exists = os.path.exists
    os_mock.pathsep = os.pathsep
    if proj_dir is None:
        os_mock.environ = {}
    else:
        os_mock.environ = {"PROJ_LIB": proj_dir}


def test_get_data_dir__missing():
    with proj_env(), pytest.raises(DataDirError), patch(
        "pyproj.datadir.find_executable", return_value=None
    ), patch("pyproj.datadir.os") as os_mock, patch("pyproj.datadir.sys") as sys_mock:
        sys_mock.prefix = _INVALID_PATH
        setup_os_mock(os_mock)
        unset_data_dir()
        assert get_data_dir() is None


def test_get_data_dir__from_user():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, patch(
        "pyproj.datadir.sys"
    ) as sys_mock, temporary_directory() as tmpdir_env:  # noqa: E501
        setup_os_mock(
            os_mock,
            abspath_return=os.path.join(tmpdir, "randomfilename.py"),
            proj_dir=tmpdir_env,
        )
        sys_mock.prefix = tmpdir_env
        create_projdb(tmpdir)
        create_projdb(tmpdir_env)
        set_data_dir(tmpdir)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        assert get_data_dir() == tmpdir


def test_get_data_dir__internal():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, temporary_directory() as tmpdir_fake, patch(
        "pyproj.datadir.sys"
    ) as sys_mock:
        setup_os_mock(
            os_mock,
            abspath_return=os.path.join(tmpdir, "randomfilename.py"),
            proj_dir=tmpdir_fake,
        )
        sys_mock.prefix = tmpdir_fake
        unset_data_dir()
        create_projdb(tmpdir)
        create_projdb(tmpdir_fake)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        assert get_data_dir() == internal_proj_dir


def test_get_data_dir__from_env_var():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, patch("pyproj.datadir.sys") as sys_mock:
        setup_os_mock(os_mock, proj_dir=tmpdir)
        sys_mock.prefix = _INVALID_PATH
        unset_data_dir()
        create_projdb(tmpdir)
        assert get_data_dir() == tmpdir


def test_get_data_dir__from_env_var__multiple():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, patch("pyproj.datadir.sys") as sys_mock:
        setup_os_mock(os_mock, proj_dir=os.pathsep.join([tmpdir, tmpdir, tmpdir]))
        sys_mock.prefix = _INVALID_PATH
        unset_data_dir()
        create_projdb(tmpdir)
        assert get_data_dir() == os.pathsep.join([tmpdir, tmpdir, tmpdir])


def test_get_data_dir__from_prefix():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, patch("pyproj.datadir.sys") as sys_mock:
        setup_os_mock(os_mock)
        unset_data_dir()
        sys_mock.prefix = tmpdir
        proj_dir = os.path.join(tmpdir, "share", "proj")
        os.makedirs(proj_dir)
        create_projdb(proj_dir)
        assert get_data_dir() == proj_dir


def test_get_data_dir__from_path():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock, patch("pyproj.datadir.sys") as sys_mock, patch(
        "pyproj.datadir.find_executable"
    ) as find_exe:
        setup_os_mock(os_mock)
        sys_mock.prefix = _INVALID_PATH
        unset_data_dir()
        find_exe.return_value = os.path.join(tmpdir, "bin", "proj")
        proj_dir = os.path.join(tmpdir, "share", "proj")
        os.makedirs(proj_dir)
        create_projdb(proj_dir)
        assert get_data_dir() == proj_dir


def test_append_data_dir__internal():
    with proj_env(), temporary_directory() as tmpdir, patch(
        "pyproj.datadir.os"
    ) as os_mock:
        setup_os_mock(os_mock, os.path.join(tmpdir, "randomfilename.py"))
        unset_data_dir()
        create_projdb(tmpdir)
        internal_proj_dir = os.path.join(tmpdir, "proj_dir", "share", "proj")
        os.makedirs(internal_proj_dir)
        create_projdb(internal_proj_dir)
        extra_datadir = str(os.path.join(tmpdir, "extra_datumgrids"))
        append_data_dir(extra_datadir)
        assert get_data_dir() == os.pathsep.join([internal_proj_dir, extra_datadir])


def test_creating_multiple_crs_without_file_limit():
    assert [CRS.from_epsg(4326) for _ in range(1200)]
{'fraction_non_alphanumeric': 0.10836155248762698, 'fraction_numerical': 0.0021707041764348354, 'mean_word_length': 3.231447465099192, 'pattern_counts': {'":': 1, '<': 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': '7180777', 'n_tokens_mistral': 4096, 'n_tokens_neox': 3969, 'n_words': 735}