<commit_before>"""Helper library which performs validation of the submission."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import csv
import json
import logging
import os
import re
import subprocess

import numpy as np
from PIL import Image

from six import iteritems
from six import PY3


EXTRACT_COMMAND = {
    '.zip': ['unzip', '${src}', '-d', '${dst}'],
    '.tar': ['tar', 'xvf', '${src}', '-C', '${dst}'],
    '.tar.gz': ['tar', 'xvzf', '${src}', '-C', '${dst}'],
}

ALLOWED_SUBMISSION_TYPES = ['attack', 'targeted_attack', 'defense']

REQUIRED_METADATA_JSON_FIELDS = ['entry_point', 'container',
                                 'container_gpu', 'type']

CMD_VARIABLE_RE = re.compile('^\\$\\{(\\w+)\\}$')

BATCH_SIZE = 8
IMAGE_NAME_PATTERN = 'IMG{0:04}.png'

ALLOWED_EPS = [4, 8, 12, 16]

MAX_SUBMISSION_SIZE_ZIPPED = 8*1024*1024*1024      #  8 GiB
MAX_SUBMISSION_SIZE_UNPACKED = 16*1024*1024*1024   # 16 GiB
MAX_DOCKER_IMAGE_SIZE = 8*1024*1024*1024           #  8 GiB


def get_extract_command_template(filename):
  """Returns extraction command based on the filename extension."""
  for k, v in iteritems(EXTRACT_COMMAND):
    if filename.endswith(k):
      return v
  return None


def shell_call(command, **kwargs):
  """Calls shell command with parameter substitution.

  Args:
    command: command to run as a list of tokens
    **kwargs: dirctionary with substitutions

  Returns:
    whether command was successful, i.e. returned 0 status code

  Example of usage:
    shell_call(['cp', '${A}', '${B}'], A='src_file', B='dst_file')
  will call shell command:
    cp src_file dst_file
  """
  command = list(command)
  for i in range(len(command)):
    m = CMD_VARIABLE_RE.match(command[i])
    if m:
      var_id = m.group(1)
      if var_id in kwargs:
        command[i] = kwargs[var_id]
  return subprocess.call(command) == 0


def make_directory_writable(dirname):
  """Makes directory readable and writable by everybody.

  Args:
    dirname: name of the directory

  Returns:
    True if operation was successfull

  If you run something inside Docker container and it writes files, then
  these files will be written as root user with restricted permissions.
  So to be able to read/modify these files outside of Docker you have to change
  permissions to be world readable and writable.
  """
  retval = shell_call(['docker', 'run', '-v',
                       '{0}:/output_dir'.format(dirname),
                       'busybox:1.27.2',
                       'chmod', '-R', 'a+rwX', '/output_dir'])
  if not retval:
    logging.error('Failed to change permissions on directory: %s', dirname)
  return retval


def load_defense_output(filename):
  """Loads output of defense from given file."""
  result = {}
  with open(filename) as f:
    for row in csv.reader(f):
      try:
        image_filename = row[0]
        if not image_filename.endswith('.png'):
          image_filename += '.png'
        label = int(row[1])
      except (IndexError, ValueError):
        continue
      result[image_filename] = label
  return result


class SubmissionValidator(object):
  """Class which performs validation of the submission."""

  def __init__(self, temp_dir, use_gpu):
    """Initializes instance of SubmissionValidator.

    Args:
      temp_dir: temporary working directory
      use_gpu: whether to use GPU
    """
    self._temp_dir = temp_dir
    self._use_gpu = use_gpu
    self._tmp_extracted_dir = os.path.join(self._temp_dir, 'tmp_extracted')
    self._extracted_submission_dir = os.path.join(self._temp_dir, 'extracted')
    self._sample_input_dir = os.path.join(self._temp_dir, 'input')
    self._sample_output_dir = os.path.join(self._temp_dir, 'output')

  def _prepare_temp_dir(self):
    """Cleans up and prepare temporary directory."""
    shell_call(['rm', '-rf', os.path.join(self._temp_dir, '*')])
    # NOTE: we do not create self._extracted_submission_dir
    # this is intentional because self._tmp_extracted_dir or it's subdir
    # will be renames into self._extracted_submission_dir
    os.mkdir(self._tmp_extracted_dir)
    os.mkdir(self._sample_input_dir)
    os.mkdir(self._sample_output_dir)
<commit_msg>Update submission validation tool<commit_after>"""Helper library which performs validation of the submission."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import csv
import json
import logging
import os
import re
import subprocess

import numpy as np
from PIL import Image

from six import iteritems
from six import PY3


EXTRACT_COMMAND = {
    '.zip': ['unzip', '${src}', '-d', '${dst}'],
    '.tar': ['tar', 'xvf', '${src}', '-C', '${dst}'],
    '.tar.gz': ['tar', 'xvzf', '${src}', '-C', '${dst}'],
}

ALLOWED_SUBMISSION_TYPES = ['attack', 'targeted_attack', 'defense']

REQUIRED_METADATA_JSON_FIELDS = ['entry_point', 'container',
                                 'container_gpu', 'type']

CMD_VARIABLE_RE = re.compile('^\\$\\{(\\w+)\\}$')

BATCH_SIZE = 8
IMAGE_NAME_PATTERN = 'IMG{0:04}.png'

ALLOWED_EPS = [4, 8, 12, 16]

MAX_SUBMISSION_SIZE_ZIPPED = 8*1024*1024*1024      #  8 GiB
MAX_SUBMISSION_SIZE_UNPACKED = 16*1024*1024*1024   # 16 GiB
MAX_DOCKER_IMAGE_SIZE = 8*1024*1024*1024           #  8 GiB


def get_extract_command_template(filename):
  """Returns extraction command based on the filename extension."""
  for k, v in iteritems(EXTRACT_COMMAND):
    if filename.endswith(k):
      return v
  return None


def shell_call(command, **kwargs):
  """Calls shell command with parameter substitution.

  Args:
    command: command to run as a list of tokens
    **kwargs: dirctionary with substitutions

  Returns:
    whether command was successful, i.e. returned 0 status code

  Example of usage:
    shell_call(['cp', '${A}', '${B}'], A='src_file', B='dst_file')
  will call shell command:
    cp src_file dst_file
  """
  command = list(command)
  for i in range(len(command)):
    m = CMD_VARIABLE_RE.match(command[i])
    if m:
      var_id = m.group(1)
      if var_id in kwargs:
        command[i] = kwargs[var_id]
  return subprocess.call(command) == 0


def make_directory_writable(dirname):
  """Makes directory readable and writable by everybody.

  Args:
    dirname: name of the directory

  Returns:
    True if operation was successfull

  If you run something inside Docker container and it writes files, then
  these files will be written as root user with restricted permissions.
  So to be able to read/modify these files outside of Docker you have to change
  permissions to be world readable and writable.
  """
  retval = shell_call(['docker', 'run', '-v',
                       '{0}:/output_dir'.format(dirname),
                       'busybox:1.27.2',
                       'chmod', '-R', 'a+rwx', '/output_dir'])
  if not retval:
    logging.error('Failed to change permissions on directory: %s', dirname)
  return retval


def load_defense_output(filename):
  """Loads output of defense from given file."""
  result = {}
  with open(filename) as f:
    for row in csv.reader(f):
      try:
        image_filename = row[0]
        if not image_filename.endswith('.png'):
          image_filename += '.png'
        label = int(row[1])
      except (IndexError, ValueError):
        continue
      result[image_filename] = label
  return result


class SubmissionValidator(object):
  """Class which performs validation of the submission."""

  def __init__(self, temp_dir, use_gpu):
    """Initializes instance of SubmissionValidator.

    Args:
      temp_dir: temporary working directory
      use_gpu: whether to use GPU
    """
    self._temp_dir = temp_dir
    self._use_gpu = use_gpu
    self._tmp_extracted_dir = os.path.join(self._temp_dir, 'tmp_extracted')
    self._extracted_submission_dir = os.path.join(self._temp_dir, 'extracted')
    self._sample_input_dir = os.path.join(self._temp_dir, 'input')
    self._sample_output_dir = os.path.join(self._temp_dir, 'output')

  def _prepare_temp_dir(self):
    """Cleans up and prepare temporary directory."""
    shell_call(['rm', '-rf', os.path.join(self._temp_dir, '*')])
    # NOTE: we do not create self._extracted_submission_dir
    # this is intentional because self._tmp_extracted_dir or it's subdir
    # will be renames into self._extracted_submission_dir
    os.mkdir(self._tmp_extracted_dir)
    os.mkdir(self._sample_input_dir)
    os.mkdir(self._sample_output_dir)
    # make output dir world writable
    shell_call(['chmod', 'a+rwX', '-R', self._sample_output_dir])

{'fraction_non_alphanumeric': 0.12026128543100431, 'fraction_numerical': 0.01516388662078619, 'mean_word_length': 3.4843096234309625, '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': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1698203', 'n_tokens_mistral': 2863, 'n_tokens_neox': 2714, 'n_words': 790}