<commit_before>import os
import re
import subprocess
import random
import string
from tempfile import mkstemp


class PdftkError(Exception):
    pass


class DuplicateFormFieldError(Exception):
    pass


class MissingFormFieldError(Exception):
    pass


class InvalidOptionError(Exception):
    pass


class TooManyPDFsError(Exception):
    pass

class InvalidAnswersError(Exception):
    pass


class PDFTKWrapper:

    def __init__(self, encoding='latin-1', tmp_path=None, clean_up=True):
        self.encoding = encoding
        self.TEMP_FOLDER_PATH = tmp_path
        self._tmp_files = []
        self._cache_fdf_for_filling = False
        self._fdf_cache = None
        self.clean_up = clean_up

    def _coerce_to_file_path(self, path_or_file_or_bytes):
        """This converst file-like objects and `bytes` into
        existing files and returns a filepath
        if strings are passed in, it is assumed that they are existing
        files
        """
        if not isinstance(path_or_file_or_bytes, str):
            if isinstance(path_or_file_or_bytes, bytes):
                return self._write_tmp_file(
                    bytestring=path_or_file_or_bytes)
            else:
                return self._write_tmp_file(
                    file_obj=path_or_file_or_bytes)
        return path_or_file_or_bytes

    def _write_tmp_file(self, file_obj=None, bytestring=None):
        """Take a file-like object or a bytestring,
        create a temporary file and return a file path.
        file-like objects will be read and written to the tempfile
        bytes objects will be written directly to the tempfile
        """
        tmp_path = self.TEMP_FOLDER_PATH
        os_int, tmp_fp = mkstemp(dir=tmp_path)
        with open(tmp_fp, 'wb') as tmp_file:
            if file_obj:
                tmp_file.write(file_obj.read())
            elif bytestring:
                tmp_file.write(bytestring)
        self._tmp_files.append(tmp_fp)
        return tmp_fp

    def clean_up_tmp_files(self):
        if not self._tmp_files:
            return
        for i in range(len(self._tmp_files)):
            path = self._tmp_files.pop()
            os.remove(path)

    def _get_file_contents(self, path, decode=False, encoding=None):
        """given a file path, return the contents of the file
        if decode is True, the contents will be decoded using the default
        encoding
        """
        bytestring = open(path, 'rb').read()
        if decode:
            return bytestring.decode(encoding or self.encoding)
        return bytestring

    def run_command(self, args):
        """Run a command to pdftk on the command line.
            `args` is a list of command line arguments.
        This method is reponsible for handling errors that arise from
        pdftk's CLI
        """
        if args[0] != 'pdftk':
            args.insert(0, 'pdftk')
        process = subprocess.Popen(args,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)<commit_msg>added customizable path to pdftk<commit_after>import os
import re
import subprocess
import random
import string
from tempfile import mkstemp


class PdftkError(Exception):
    pass


class DuplicateFormFieldError(Exception):
    pass


class MissingFormFieldError(Exception):
    pass


class InvalidOptionError(Exception):
    pass


class TooManyPDFsError(Exception):
    pass

class InvalidAnswersError(Exception):
    pass


class PDFTKWrapper:

    def __init__(self, encoding='latin-1', tmp_path=None, clean_up=True):
        self.encoding = encoding
        self.TEMP_FOLDER_PATH = tmp_path
        self._tmp_files = []
        self._cache_fdf_for_filling = False
        self._fdf_cache = None
        self.clean_up = clean_up
        self.PDFTK_PATH = os.environ.get('PDFTK_PATH', 'pdftk')

    def _coerce_to_file_path(self, path_or_file_or_bytes):
        """This converst file-like objects and `bytes` into
        existing files and returns a filepath
        if strings are passed in, it is assumed that they are existing
        files
        """
        if not isinstance(path_or_file_or_bytes, str):
            if isinstance(path_or_file_or_bytes, bytes):
                return self._write_tmp_file(
                    bytestring=path_or_file_or_bytes)
            else:
                return self._write_tmp_file(
                    file_obj=path_or_file_or_bytes)
        return path_or_file_or_bytes

    def _write_tmp_file(self, file_obj=None, bytestring=None):
        """Take a file-like object or a bytestring,
        create a temporary file and return a file path.
        file-like objects will be read and written to the tempfile
        bytes objects will be written directly to the tempfile
        """
        tmp_path = self.TEMP_FOLDER_PATH
        os_int, tmp_fp = mkstemp(dir=tmp_path)
        with open(tmp_fp, 'wb') as tmp_file:
            if file_obj:
                tmp_file.write(file_obj.read())
            elif bytestring:
                tmp_file.write(bytestring)
        self._tmp_files.append(tmp_fp)
        return tmp_fp

    def clean_up_tmp_files(self):
        if not self._tmp_files:
            return
        for i in range(len(self._tmp_files)):
            path = self._tmp_files.pop()
            os.remove(path)

    def _get_file_contents(self, path, decode=False, encoding=None):
        """given a file path, return the contents of the file
        if decode is True, the contents will be decoded using the default
        encoding
        """
        bytestring = open(path, 'rb').read()
        if decode:
            return bytestring.decode(encoding or self.encoding)
        return bytestring

    def run_command(self, args):
        """Run a command to pdftk on the command line.
            `args` is a list of command line arguments.
        This method is reponsible for handling errors that arise from
        pdftk's CLI
        """
        if args[0] != self.PDFTK_PATH:
            args.insert(0, self.PDFTK_PATH)
        process = subprocess.Popen(args,
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
{'fraction_non_alphanumeric': 0.07069050352632442, 'fraction_numerical': 0.0009840905363293422, 'mean_word_length': 2.339539978094195, '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': '7279924', 'n_tokens_mistral': 1813, 'n_tokens_neox': 1760, 'n_words': 498}