<commit_before>import json

from django import forms
from django.conf import settings
from django.http import HttpResponse
from django.views.generic import TemplateView
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext

from catmaid.control.common import get_class_to_id_map, get_relation_to_id_map
from catmaid.control.common import insert_into_log
from catmaid.control.ajax_templates import *
from catmaid.control.ontology import get_class_links_qs
from catmaid.models import Class, ClassClass, ClassInstance, ClassInstanceClassInstance
from catmaid.models import Relation, UserRole, Project, Restriction, Stack
from catmaid.models import CardinalityRestriction, RegionOfInterest
from catmaid.models import RegionOfInterestClassInstance
from catmaid.control.authentication import requires_user_role
from catmaid.control.roi import link_roi_to_class_instance

# All needed classes by the classification system alongside their
# descriptions.
needed_classes = {
    'classification_root':
         "The root node class for classification graphs",
    'classification_project':
         "A project represention to link to classification graphs"}

# All needed relations by the classification system alongside their
# descriptions.
needed_relations = {
    'is_a': "A basic is_a relation",
    'classified_by': "Link a classification to something",
    'linked_to': "Links a ROI to a class instance."}

class ClassProxy(Class):
    """ A proxy class to allow custom labeling of class in model forms.
    """
    class Meta:
        proxy=True

    def __unicode__(self):
        return "{0} ({1})".format(self.class_name, str(self.id))

class ClassInstanceClassInstanceProxy(ClassInstanceClassInstance):
    """ A proxy class to allow custom labeling of links between class
    instance objects in model forms.
    """
    class Meta:
        proxy=True

    def __unicode__(self):
        # Basic result string
        if len(self.class_instance_b.name) > 0:
            name = self.class_instance_b.name
        else:
            name = self.class_instance_b.class_column.class_name
        result = "{0} ({1})".format(name, str(self.id))

        # Display referce count if wanted
        display_refs = True
        if display_refs:
            # Get projects that are linked to this CI (expect it to be
            # a classification root)
            num_links = ClassInstanceClassInstance.objects.filter(
                class_instance_b=self.class_instance_b,
                relation__relation_name='classified_by').count()
            result = "{0} Refs: {1}".format(result, str(num_links))

        return result

def get_root_classes_count(workspace_pid):
    """ Return the number of available root classes for the given workspace
    project.
    """
    return get_class_links_qs(workspace_pid, 'is_a', 'classification_root').count()

def get_root_classes_qs(workspace_pid):
    """ Return a queryset that will get all root classes for the
    given workspace project.
    """
    return[ c.class_a.id for c in get_class_links_qs(workspace_pid, 'is_a', 'classification_root') ]

def get_classification_links_qs( workspace_pid, project_id, inverse=False ):
    """ Returns a list of CICI links that link a classification graph
    with a project. The classification system uses a dummy project with
    ID -1 to store its ontologies and class instances. Each project using
    a particular classification graph instance creates a class instance
    with its PID of class classification_project (which lives in dummy
    project -1) and links to a classification root. A query set for those
    links will be returned. If <inverse> is set to true, only those
    classification graph links will be returned that *don't* belong to
    the project with <project_id>.
    """
    # Expect the classification system to be set up and expect one
    # single 'classification_project' class.
    classification_project_c_q = Class.objects.filter(
        project_id = workspace_pid, class_name = 'classification_project')
    # Return an empty list if there isn't a classification project class
    if classification_project_c_q.count() == 0:
        return []
    classification_project_c = classification_project_c_q[0]

    # Get the query set for the classification project instance to test
    # if there already is such an instance.
    if inverse:
        classification_project_ci_q = ClassInstance.objects.filter(
            class_column_id = classification_project_c.id).exclude(
                project_id = project_id)
    else:
        classification_project_ci_q = ClassInstance.objects.filter(
            project_id = project_id, class_column_id = classification_project_c.id)
    # Return an empty list if there isn't a classification project
    # instance
    if classification_project_ci_q.count() == 0:
        return []
    classification_project_ci = classification_project_ci_q[0]

    # Get a list of all classification root classes and return an empty
    # list if teher are none
    root_class_links = get_class_links_qs(workspace_pid, 'is_a', 'classification_root')
    root_classes = [cc.class_a for cc in root_class_links]
    if not root_classes:
        return []
    # Query to get all root class instances
    root_class_instances = ClassInstance.objects.filter(project_id=workspace_pid,
        class_column__in=root_classes)
    # Query to get the 'classified_by' relation
    classified_by_rel = Relation.objects.filter(project_id=workspace_pid,
        relation_name='classified_by')
    # Find all 'classification_project' class instances of the current
    # project that link to those root nodes
    cici_q = ClassInstanceClassInstance.objects.filter(project_id=workspace_pid,
        relation__in=classified_by_rel, class_instance_b__in=root_class_instances,
        class_instance_a__in=classification_project_ci_q)

    return cici_q

def get_classification_roots( workspace_pid, project_id ):
    """ Returns a list of classification graph roots, linked to a
    project. The classification system uses a dummy project with ID -1
    to store its ontologies and class instances. Each project using a
    particular classification graph instance creates a class instance
    with its PID of class classification_project (which lives in dummy
    project -1). Those class instances will be returned.
    """
    # Get all links
    links_q = get_classification_links_qs( workspace_pid, project_id )
    # Return valid roots
    return [ cici.class_instance_a for cici in links_q ]

def get_classification_number( project_id ):
    """ Returns the number of classification graphs, linked to a
    project.
    """
    roots = get_classification_roots(project_id)<commit_msg>Classifications: add support for root retrieval of project lists<commit_after>import json

from django import forms
from django.conf import settings
from django.http import HttpResponse
from django.views.generic import TemplateView
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.db.models import Count

from catmaid.control.common import get_class_to_id_map, get_relation_to_id_map
from catmaid.control.common import insert_into_log
from catmaid.control.ajax_templates import *
from catmaid.control.ontology import get_class_links_qs
from catmaid.models import Class, ClassClass, ClassInstance, ClassInstanceClassInstance
from catmaid.models import Relation, UserRole, Project, Restriction, Stack
from catmaid.models import CardinalityRestriction, RegionOfInterest
from catmaid.models import RegionOfInterestClassInstance
from catmaid.control.authentication import requires_user_role
from catmaid.control.roi import link_roi_to_class_instance

# All needed classes by the classification system alongside their
# descriptions.
needed_classes = {
    'classification_root':
         "The root node class for classification graphs",
    'classification_project':
         "A project represention to link to classification graphs"}

# All needed relations by the classification system alongside their
# descriptions.
needed_relations = {
    'is_a': "A basic is_a relation",
    'classified_by': "Link a classification to something",
    'linked_to': "Links a ROI to a class instance."}

class ClassProxy(Class):
    """ A proxy class to allow custom labeling of class in model forms.
    """
    class Meta:
        proxy=True

    def __unicode__(self):
        return "{0} ({1})".format(self.class_name, str(self.id))

class ClassInstanceClassInstanceProxy(ClassInstanceClassInstance):
    """ A proxy class to allow custom labeling of links between class
    instance objects in model forms.
    """
    class Meta:
        proxy=True

    def __unicode__(self):
        # Basic result string
        if len(self.class_instance_b.name) > 0:
            name = self.class_instance_b.name
        else:
            name = self.class_instance_b.class_column.class_name
        result = "{0} ({1})".format(name, str(self.id))

        # Display referce count if wanted
        display_refs = True
        if display_refs:
            # Get projects that are linked to this CI (expect it to be
            # a classification root)
            num_links = ClassInstanceClassInstance.objects.filter(
                class_instance_b=self.class_instance_b,
                relation__relation_name='classified_by').count()
            result = "{0} Refs: {1}".format(result, str(num_links))

        return result

def get_root_classes_count(workspace_pid):
    """ Return the number of available root classes for the given workspace
    project.
    """
    return get_class_links_qs(workspace_pid, 'is_a', 'classification_root').count()

def get_root_classes_qs(workspace_pid):
    """ Return a queryset that will get all root classes for the
    given workspace project.
    """
    return[ c.class_a.id for c in get_class_links_qs(workspace_pid, 'is_a', 'classification_root') ]

def get_classification_links_qs( workspace_pid, project_ids, inverse=False ):
    """ Returns a list of CICI links that link a classification graph with a
    project or a list/set of projects (project_ids can be int, list and set).
    The classification system uses a dummy project (usually with ID -1) to
    store its ontologies and class instances. Each project using a particular
    classification graph instance creates a class instance with its PID of
    class classification_project (which lives in dummy project -1) and links to
    a classification root. A query set for those links will be returned. If
    <inverse> is set to true, only those classification graph links will be
    returned that *don't* belong to the project with <project_id>.
    """
    # Make sure we deal with a list of project ids
    if not isinstance(project_ids, list) and not isinstance(project_ids, set):
        project_ids = [project_ids]

    # Expect the classification system to be set up and expect one
    # single 'classification_project' class.
    classification_project_c_q = Class.objects.filter(
        project_id = workspace_pid, class_name = 'classification_project')
    # Return an empty query set if there isn't a classification project class
    # len() is used on purpose, we need the object later anyway.
    if len(classification_project_c_q) == 0:
        return ClassInstanceClassInstance.objects.none()
    classification_project_c = classification_project_c_q[0]

    # Get the query set for the classification project instance to test
    # if there already is such an instance.
    if inverse:
        classification_project_cis_q = ClassInstance.objects.filter(
            class_column_id=classification_project_c.id).exclude(
                project_id__in=project_ids)
    else:
        classification_project_cis_q = ClassInstance.objects.filter(
            project_id__in=project_ids,
                class_column_id=classification_project_c.id)
    # Return an empty query set if there aren't classification project
    # instances available.
    if classification_project_cis_q.count() == 0:
        return ClassInstanceClassInstance.objects.none()

    # Get a list of all classification root classes and return an empty
    # list if teher are none
    root_class_links = get_class_links_qs(workspace_pid, 'is_a', 'classification_root')
    root_classes = [cc.class_a for cc in root_class_links]
    if not root_classes:
        return []
    # Query to get all root class instances
    root_class_instances = ClassInstance.objects.filter(project_id=workspace_pid,
        class_column__in=root_classes)
    # Query to get the 'classified_by' relation
    classified_by_rel = Relation.objects.filter(project_id=workspace_pid,
        relation_name='classified_by')
    # Find all 'classification_project' class instances of all requested
    # projects that link to those root nodes
    cici_q = ClassInstanceClassInstance.objects.filter(project_id=workspace_pid,
        relation__in=classified_by_rel, class_instance_b__in=root_class_instances,
        class_instance_a__in=classification_project_cis_q)

    return cici_q

def get_classification_roots( workspace_pid, project_id ):
    """ Returns a list of classification graph roots, linked to a
    project. The classification system uses a dummy project with ID -1
    to store its ontologies and class instances. Each project using a
    particular classification graph instance creates a class instance
    with its PID of class classification_project (which lives in dummy
    project -1). Those class instances will be returned.
    """
    # Get all links
    links_q = get_classification_links_qs( workspace_pid, project_id )
    # Return valid roots
    return [ cici.class_instance_a for cici in links_q ]

def get_classification_number( project_id ):
    """ Returns the number of classification graphs, linked to a
    project.
    """
    roots = get_classification_roots(project_id)
{'fraction_non_alphanumeric': 0.06264269406392695, 'fraction_numerical': 0.002497146118721461, 'mean_word_length': 3.7612092391304346, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, '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': '7655299', 'n_tokens_mistral': 3810, 'n_tokens_neox': 3662, 'n_words': 1293}