<commit_before>import os, sys
from os.path import join, dirname, exists
try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
import tempfile
import shutil

from babel.messages import pofile
from android2po import program as a2po
from android2po.convert import read_xml


__all__ = ('ProgramTest', 'TempProject', 'SystemExitCaught', 'NonZeroReturned',)



class SystemExitCaught(Exception):
    pass


class NonZeroReturned(Exception):
    pass


def mkfile(path, content=''):
    f = open(path, 'w')
    f.write(content)
    f.flush()
    f.close()


class Tee(object):
    """Return a stdout-compatible object that will pipe data written
    into it to all of the file-objects in ``args``."""

    def __init__(self, *args):
        self.args = args

    def write(self, data):
        for f in self.args:
            f.write(data)


class TempProject(object):
    """Represents a dummy-Android project in a temporary directory that
    we can run our command line tool on.
    """

    def __init__(self, manifest=True, resource_dir='res', locale_dir='locale',
                 config=None, default_xml={}, xml_langs=[]):
        self.dir = dir = tempfile.mkdtemp()
        self.locale_dir = self.p(locale_dir)
        self.resource_dir = self.p(resource_dir)

        if manifest:
            mkfile(self.p('AndroidManifest.xml'))
        if config is not None:
            self.write_config(config)

        os.mkdir(self.locale_dir)
        os.mkdir(self.resource_dir)
        if default_xml not in (False, None):
            self.write_xml(default_xml)
        # Language-XML files that should be created by default
        for code in xml_langs:
            self.write_xml(lang=code)

    def __del__(self):
        self.delete()

    def delete(self):
        """Delete all the files of this temporary project.
        """
        if os.path.exists(self.dir):
            shutil.rmtree(self.dir)

    def p(self, *w):
        """Join a path relative to the project directory.
        """
        return join(self.dir, *w)

    def write_config(self, config):
        """Write a configuration file.
        """
        if isinstance(config, (list, tuple)):
            config = "\n".join(config)
        mkfile(self.p('.android2po'), config)

    def write_xml(self, data={}, lang=None, kind='strings'):
        if isinstance(data, basestring):
            content = data
        else:
            # Could use the more robust XML writing functions from
            # android2po.convert.
            content = '<resources>'
            for k, v in data.iteritems():
                content += '<string name="%s">%s</string>' % (k, v)
            content += '</resources>'

        folder = 'values'
        if lang:
            folder = "%s-%s" % (folder, lang)
        filename = self.p(self.resource_dir, folder, '%s.xml' % kind)
        if not exists(dirname(filename)):
            os.makedirs(dirname(filename))
        mkfile(filename, content)

    def write_po(self, catalog, filename):
        file = open(join(self.locale_dir, '%s' % filename), 'wb')
        try:
            return pofile.write_po(file, catalog)
        finally:
            file.close()

    def program(self, command=None, kwargs={}):
        """Run android2po in this project's working directory.

        Return the program output.
        """
        args = ['a2po-test']
        if command:
            args.append(command)
        for k, v in kwargs.iteritems():
            if v is True or not v:
                args.append(k)
            else:
                if not isinstance(v, (list, tuple)):
                    # A tuple may be used to pass the same argument multiple
                    # times with different values.
                    v = [v]
                for w in v:
                    if isinstance(w, (list, tuple)):
                        # This is starting to get messy, but this allows the
                        # caller to generate "--arg val1 val2" by passing as
                        # the dict: {'arg': [['val1', 'val2']]}
                        args.append('%s' % k)
                        args.extend(w)
                    else:
                        # Otherwise, we set a single value, and we use "=",
                        # so that arguments that are defined as nargs='+'
                        # will not capture more than the value "w".
                        args.append("%s=%s" % (k, w))

        old_cwd = os.getcwd()
        os.chdir(self.dir)
        # Sometimes we might want to check a certain message was printed
        # out, so in addition to having nose capture the output, we
        # want to as well.
        old_stdout = sys.stdout
        stdout_capture = StringIO.StringIO()
        sys.stdout = Tee(sys.stdout, stdout_capture)
        # argparse likes to write to stderr, let it be handled like
        # normal stdout (i.e. captured by nose as well as us).
        old_stderr = sys.stderr
        sys.stderr = sys.stdout
        try:
            try:<commit_msg>Have the command line be printed during tests. This is helpful for debugging failures.<commit_after>import os, sys
from os.path import join, dirname, exists
try:
    import cStringIO as StringIO
except ImportError:
    import StringIO
import tempfile
import shutil

from babel.messages import pofile
from android2po import program as a2po
from android2po.convert import read_xml


__all__ = ('ProgramTest', 'TempProject', 'SystemExitCaught', 'NonZeroReturned',)



class SystemExitCaught(Exception):
    pass


class NonZeroReturned(Exception):
    pass


def mkfile(path, content=''):
    f = open(path, 'w')
    f.write(content)
    f.flush()
    f.close()


class Tee(object):
    """Return a stdout-compatible object that will pipe data written
    into it to all of the file-objects in ``args``."""

    def __init__(self, *args):
        self.args = args

    def write(self, data):
        for f in self.args:
            f.write(data)


class TempProject(object):
    """Represents a dummy-Android project in a temporary directory that
    we can run our command line tool on.
    """

    def __init__(self, manifest=True, resource_dir='res', locale_dir='locale',
                 config=None, default_xml={}, xml_langs=[]):
        self.dir = dir = tempfile.mkdtemp()
        self.locale_dir = self.p(locale_dir)
        self.resource_dir = self.p(resource_dir)

        if manifest:
            mkfile(self.p('AndroidManifest.xml'))
        if config is not None:
            self.write_config(config)

        os.mkdir(self.locale_dir)
        os.mkdir(self.resource_dir)
        if default_xml not in (False, None):
            self.write_xml(default_xml)
        # Language-XML files that should be created by default
        for code in xml_langs:
            self.write_xml(lang=code)

    def __del__(self):
        self.delete()

    def delete(self):
        """Delete all the files of this temporary project.
        """
        if os.path.exists(self.dir):
            shutil.rmtree(self.dir)

    def p(self, *w):
        """Join a path relative to the project directory.
        """
        return join(self.dir, *w)

    def write_config(self, config):
        """Write a configuration file.
        """
        if isinstance(config, (list, tuple)):
            config = "\n".join(config)
        mkfile(self.p('.android2po'), config)

    def write_xml(self, data={}, lang=None, kind='strings'):
        if isinstance(data, basestring):
            content = data
        else:
            # Could use the more robust XML writing functions from
            # android2po.convert.
            content = '<resources>'
            for k, v in data.iteritems():
                content += '<string name="%s">%s</string>' % (k, v)
            content += '</resources>'

        folder = 'values'
        if lang:
            folder = "%s-%s" % (folder, lang)
        filename = self.p(self.resource_dir, folder, '%s.xml' % kind)
        if not exists(dirname(filename)):
            os.makedirs(dirname(filename))
        mkfile(filename, content)

    def write_po(self, catalog, filename):
        file = open(join(self.locale_dir, '%s' % filename), 'wb')
        try:
            return pofile.write_po(file, catalog)
        finally:
            file.close()

    def program(self, command=None, kwargs={}):
        """Run android2po in this project's working directory.

        Return the program output.
        """
        args = ['a2po-test']
        if command:
            args.append(command)
        for k, v in kwargs.iteritems():
            if v is True or not v:
                args.append(k)
            else:
                if not isinstance(v, (list, tuple)):
                    # A tuple may be used to pass the same argument multiple
                    # times with different values.
                    v = [v]
                for w in v:
                    if isinstance(w, (list, tuple)):
                        # This is starting to get messy, but this allows the
                        # caller to generate "--arg val1 val2" by passing as
                        # the dict: {'arg': [['val1', 'val2']]}
                        args.append('%s' % k)
                        args.extend(w)
                    else:
                        # Otherwise, we set a single value, and we use "=",
                        # so that arguments that are defined as nargs='+'
                        # will not capture more than the value "w".
                        args.append("%s=%s" % (k, w))

        old_cwd = os.getcwd()
        os.chdir(self.dir)
        # Sometimes we might want to check a certain message was printed
        # out, so in addition to having nose capture the output, we
        # want to as well.
        old_stdout = sys.stdout
        stdout_capture = StringIO.StringIO()
        sys.stdout = Tee(sys.stdout, stdout_capture)
        # argparse likes to write to stderr, let it be handled like
        # normal stdout (i.e. captured by nose as well as us).
        old_stderr = sys.stderr
        sys.stderr = sys.stdout
        try:
            try:
                print "Running: %s" % " ".join(args)
{'fraction_non_alphanumeric': 0.10589156390683108, 'fraction_numerical': 0.002153063221765512, 'mean_word_length': 1.8520792631872733, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 22}, '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': '717724', 'n_tokens_mistral': 2883, 'n_tokens_neox': 2800, 'n_words': 918}