<commit_before>import objc
import os
import urllib
import urlparse
import zipfile

# noinspection PyUnresolvedReferences
from AppKit import (
    NSRegisterServicesProvider,
    NSPasteboardURLReadingFileURLsOnlyKey,
    NSPasteboardURLReadingContentsConformToTypesKey,
)
from enum import Enum
# noinspection PyUnresolvedReferences
from Foundation import (
    NSObject, NSLog, NSURL, NSNumber, NSMutableDictionary,
    NSURLTypeIdentifierKey,
)
from PyObjCTools import AppHelper


class UniformTypeIdentifier(Enum):
    zip = 'public.zip-archive'
    rar = 'com.rarlab.rar-archive'


def service_selector(fn):
    """
    Set the selector signature to be that of a service

    Signature copied from:
    https://pythonhosted.org/pyobjc/examples/Cocoa/AppKit/SimpleService/index.html

    :param fn: the service
    :return: an objc-ified service method
    """
    return objc.selector(fn, signature='v@:@@o^@')


class RenameArchiveService(NSObject):
    # noinspection PyPep8Naming
    @service_selector
    def openRenameArchiveDialog_userData_error_(self, pasteboard, data, error):
        # We only care about file URLs with UTI that we recognize
        file_urls = get_file_urls_from_pasteboard(pasteboard, [UniformTypeIdentifier.zip.value])
        if not file_urls:
            NSLog("None of the selected files had a supported Uniform Type Identifier:")
            unsupported_urls = get_file_urls_from_pasteboard(pasteboard)
            for url in unsupported_urls:
                NSLog("- %@ (%@)", url.filePathURL().absoluteString(), get_uniform_type_identifier(url))
            return

        # We only deal with the first of the selected files.
        # Finder gives us stuff like "file:///.file/id=...", so we turn it into the path URL
        file_url = file_urls[0].filePathURL()
        file_uti = get_uniform_type_identifier(file_url)

        NSLog("Selected: %@", file_url.absoluteString())
        NSLog("UTI: %@", file_uti)

        # modules don't like dealing with the escaped path strings
        file_path = get_file_path(file_url)

        directory_names = []
        if file_uti == UniformTypeIdentifier.zip.value:
            directory_names = get_zip_directory_names(file_path)
        elif file_uti == UniformTypeIdentifier.rar.value:
            NSLog("RAR isn't supported yet!")

        NSLog("Dumping directory names in %@:", file_path)
        for d in directory_names:
            NSLog("- %@", d)
        return


def get_file_urls_from_pasteboard(pasteboard, desired_uti_types=None):
    """
    Returns the file NSURL objects in the pasteboard.
    Specify the optional desired_uti_types is a list of UTI strings to only return
    :param NSPasteboard pasteboard: pasteboard
    :param desired_uti_types: a list of UTIs in string form
    :type desired_uti_types: list of Uniform Type Identifier strings
    :return: a list of NSURL objects satisfying the desired_uti_types restriction (if any)
    :rtype: list of NSURL
    """
    options = NSMutableDictionary.dictionaryWithCapacity_(2)
    options.setObject_forKey_(NSNumber.numberWithBool_(True),
                              NSPasteboardURLReadingFileURLsOnlyKey)
    if desired_uti_types:
        options.setObject_forKey_(desired_uti_types,
                                  NSPasteboardURLReadingContentsConformToTypesKey)
    nsurls = pasteboard.readObjectsForClasses_options_([NSURL], options)
    return nsurls


def get_uniform_type_identifier(file_url):
    """
    Gets the resource's uniform type identifier
    :param NSURL file_url: URL to a file
    :return: the resource's uniform type identifier as a str or None
    """
    return file_url.getResourceValue_forKey_error_(None, NSURLTypeIdentifierKey, None)[1]


def get_file_path(nsurl):
    """
    Gets the unescaped absolute path of a NSURL

    :param NSURL nsurl: a file NSURL
    :return: unescaped absolute path string
    """
    escaped_path = nsurl.path()
    return urllib.unquote(urlparse.urlparse(escaped_path).path)


def get_zip_directory_names(file_path):
    """
    Gets the list of directories inside a ZIP archive
    Reads the directory names inside of a ZIP archive, and returns a list of
    each directory name (without its parent directories).

    :param str file_path: A string that can be a relative filename or file path (it
        doesn't matter as long as this script can read it) of a ZIP file
    :return: a list of directory name strings.<commit_msg>better format for doc strings<commit_after>import objc
import os
import urllib
import urlparse
import zipfile

# noinspection PyUnresolvedReferences
from AppKit import (
    NSRegisterServicesProvider,
    NSPasteboardURLReadingFileURLsOnlyKey,
    NSPasteboardURLReadingContentsConformToTypesKey,
)
from enum import Enum
# noinspection PyUnresolvedReferences
from Foundation import (
    NSObject, NSLog, NSURL, NSNumber, NSMutableDictionary,
    NSURLTypeIdentifierKey,
)
from PyObjCTools import AppHelper


class UniformTypeIdentifier(Enum):
    zip = 'public.zip-archive'
    rar = 'com.rarlab.rar-archive'


def service_selector(fn):
    """Set the selector signature to be that of a service

    Signature copied from:
    https://pythonhosted.org/pyobjc/examples/Cocoa/AppKit/SimpleService/index.html

    :param fn: the service
    :return: an objc-ified service method
    """
    return objc.selector(fn, signature='v@:@@o^@')


class RenameArchiveService(NSObject):
    # noinspection PyPep8Naming
    @service_selector
    def openRenameArchiveDialog_userData_error_(self, pasteboard, data, error):
        # We only care about file URLs with UTI that we recognize
        file_urls = get_file_urls_from_pasteboard(pasteboard, [UniformTypeIdentifier.zip.value])
        if not file_urls:
            NSLog("None of the selected files had a supported Uniform Type Identifier:")
            unsupported_urls = get_file_urls_from_pasteboard(pasteboard)
            for url in unsupported_urls:
                NSLog("- %@ (%@)", url.filePathURL().absoluteString(), get_uniform_type_identifier(url))
            return

        # We only deal with the first of the selected files.
        # Finder gives us stuff like "file:///.file/id=...", so we turn it into the path URL
        file_url = file_urls[0].filePathURL()
        file_uti = get_uniform_type_identifier(file_url)

        NSLog("Selected: %@", file_url.absoluteString())
        NSLog("UTI: %@", file_uti)

        # modules don't like dealing with the escaped path strings
        file_path = get_file_path(file_url)

        directory_names = []
        if file_uti == UniformTypeIdentifier.zip.value:
            directory_names = get_zip_directory_names(file_path)
        elif file_uti == UniformTypeIdentifier.rar.value:
            NSLog("RAR isn't supported yet!")

        NSLog("Dumping directory names in %@:", file_path)
        for d in directory_names:
            NSLog("- %@", d)
        return


def get_file_urls_from_pasteboard(pasteboard, desired_uti_types=None):
    """Return the file NSURL objects in the pasteboard.
    Specify the optional desired_uti_types is a list of UTI strings to only return

    :param NSPasteboard pasteboard: pasteboard
    :param desired_uti_types: a list of UTIs in string form
    :type desired_uti_types: list of Uniform Type Identifier strings
    :return: a list of NSURL objects satisfying the desired_uti_types restriction (if any)
    :rtype: list of NSURL
    """
    options = NSMutableDictionary.dictionaryWithCapacity_(2)
    options.setObject_forKey_(NSNumber.numberWithBool_(True),
                              NSPasteboardURLReadingFileURLsOnlyKey)
    if desired_uti_types:
        options.setObject_forKey_(desired_uti_types,
                                  NSPasteboardURLReadingContentsConformToTypesKey)
    nsurls = pasteboard.readObjectsForClasses_options_([NSURL], options)
    return nsurls


def get_uniform_type_identifier(file_url):
    """Get the resource's uniform type identifier

    :param NSURL file_url: URL to a file
    :return: the resource's uniform type identifier as a str or None
    """
    return file_url.getResourceValue_forKey_error_(None, NSURLTypeIdentifierKey, None)[1]


def get_file_path(nsurl):
    """Get the unescaped absolute path of a NSURL

    :param NSURL nsurl: a file NSURL
    :return: unescaped absolute path string
    """
    escaped_path = nsurl.path()
    return urllib.unquote(urlparse.urlparse(escaped_path).path)


def get_zip_directory_names(file_path):
    """Get the list of directories inside a ZIP archive.
    First reads the directory names inside of a ZIP archive, and then returns a list of
    each directory name (without its parent directories).

    :param str file_path: A string that can be a relative filename or file path (it
        doesn't matter as long as this script can read it) of a ZIP file
    :return: a list of directory name strings.
{'fraction_non_alphanumeric': 0.07210945385219245, 'fraction_numerical': 0.000897162722888864, 'mean_word_length': 3.4083044982698962, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, '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': '2756404', 'n_tokens_mistral': 2625, 'n_tokens_neox': 2530, 'n_words': 773}