<commit_before>from collections import defaultdict
from copy import deepcopy
import itertools
import logging
from casexml.apps.case import const
from casexml.apps.case.models import CommCareCase
from casexml.apps.phone.caselogic import get_footprint
from casexml.apps.phone.data_providers.case.stock import get_stock_payload
from corehq.toggles import ENABLE_LOADTEST_USERS
from dimagi.utils.couch.database import get_safe_write_kwargs
from casexml.apps.phone import xml
from casexml.apps.phone.models import CaseState
from corehq.util.dates import iso_string_to_datetime
from dimagi.utils.parsing import string_to_utc_datetime


logger = logging.getLogger(__name__)


def get_case_payload_batched(restore_state, stock_settings):
    response = restore_state.restore_class()

    sync_operation = BatchedCaseSyncOperation(restore_state)
    factor = _get_loadtest_factor(restore_state.domain, restore_state.user)
    for update in sync_operation.get_all_case_updates():
        current_count = 0
        original_update = update
        while current_count < factor:
            element = xml.get_case_element(update.case, update.required_updates, restore_state.version)
            response.append(element)
            current_count += 1
            if current_count < factor:
                update = _transform_loadtest_update(original_update, current_count)

    sync_state = sync_operation.global_state
    restore_state.current_sync_log.cases_on_phone = sync_state.actual_owned_cases
    restore_state.current_sync_log.dependent_cases_on_phone = sync_state.actual_extended_cases
    restore_state.current_sync_log.save(**get_safe_write_kwargs())

    # commtrack balance sections
    commtrack_elements = get_stock_payload(restore_state.domain, stock_settings, sync_state.all_synced_cases)
    response.extend(commtrack_elements)

    return response, sync_operation.batch_count


def _get_loadtest_factor(domain, user):
    """
    Gets the loadtest factor for a domain and user. Is always 1 unless
    both the toggle is enabled for the domain, and the user has a non-zero,
    non-null factor set.
    """
    if domain and ENABLE_LOADTEST_USERS.enabled(domain.name):
        return getattr(user, 'loadtest_factor', 1) or 1
    return 1


def _transform_loadtest_update(update, factor):
    """
    Returns a new CaseSyncUpdate object (from an existing one) with all the
    case IDs and names mapped to have the factor appended.
    """
    def _map_id(id, count):
        return '{}-{}'.format(id, count)
    case = CommCareCase.wrap(deepcopy(update.case._doc))
    case._id = _map_id(case._id, factor)
    for index in case.indices:
        index.referenced_id = _map_id(index.referenced_id, factor)
    case.name = '{} ({})'.format(case.name, factor)
    return CaseSyncUpdate(case, update.sync_token, required_updates=update.required_updates)


class CaseSyncUpdate(object):
    """
    The record of how a case should sync
    """
    def __init__(self, case, sync_token, required_updates=None):
        self.case = case
        self.sync_token = sync_token
        # cache this property since computing it can be expensive
        self.required_updates = required_updates if required_updates is not None else self._get_required_updates()


    def _get_required_updates(self):
        """
        Returns a list of the required updates for this case/token
        pairing. Should be a list of actions like [create, update, close]
        """
        ret = []
        if not self.sync_token or not self.sync_token.phone_has_case(self.case.get_id):
            ret.append(const.CASE_ACTION_CREATE)
        # always include an update
        ret.append(const.CASE_ACTION_UPDATE)
        if self.case.closed:
            ret.append(const.CASE_ACTION_CLOSE)
        return ret


class GlobalSyncState(object):
    """
    Object containing global state for a BatchedCaseSyncOperation.

    Used within the batches to ensure uniqueness of cases being synced.

    Also used after the sync is complete to provide list of CaseState objects
    """
    def __init__(self, last_sync, case_sharing=False):<commit_msg>[ci skip] more lint<commit_after>from collections import defaultdict
from copy import deepcopy
import itertools
import logging
from casexml.apps.case import const
from casexml.apps.case.models import CommCareCase
from casexml.apps.phone.caselogic import get_footprint
from casexml.apps.phone.data_providers.case.stock import get_stock_payload
from corehq.toggles import ENABLE_LOADTEST_USERS
from dimagi.utils.couch.database import get_safe_write_kwargs
from casexml.apps.phone import xml
from casexml.apps.phone.models import CaseState
from corehq.util.dates import iso_string_to_datetime
from dimagi.utils.parsing import string_to_utc_datetime


logger = logging.getLogger(__name__)


def get_case_payload_batched(restore_state, stock_settings):
    response = restore_state.restore_class()

    sync_operation = BatchedCaseSyncOperation(restore_state)
    factor = _get_loadtest_factor(restore_state.domain, restore_state.user)
    for update in sync_operation.get_all_case_updates():
        current_count = 0
        original_update = update
        while current_count < factor:
            element = xml.get_case_element(update.case, update.required_updates, restore_state.version)
            response.append(element)
            current_count += 1
            if current_count < factor:
                update = _transform_loadtest_update(original_update, current_count)

    sync_state = sync_operation.global_state
    restore_state.current_sync_log.cases_on_phone = sync_state.actual_owned_cases
    restore_state.current_sync_log.dependent_cases_on_phone = sync_state.actual_extended_cases
    restore_state.current_sync_log.save(**get_safe_write_kwargs())

    # commtrack balance sections
    commtrack_elements = get_stock_payload(restore_state.domain, stock_settings, sync_state.all_synced_cases)
    response.extend(commtrack_elements)

    return response, sync_operation.batch_count


def _get_loadtest_factor(domain, user):
    """
    Gets the loadtest factor for a domain and user. Is always 1 unless
    both the toggle is enabled for the domain, and the user has a non-zero,
    non-null factor set.
    """
    if domain and ENABLE_LOADTEST_USERS.enabled(domain.name):
        return getattr(user, 'loadtest_factor', 1) or 1
    return 1


def _transform_loadtest_update(update, factor):
    """
    Returns a new CaseSyncUpdate object (from an existing one) with all the
    case IDs and names mapped to have the factor appended.
    """
    def _map_id(id, count):
        return '{}-{}'.format(id, count)
    case = CommCareCase.wrap(deepcopy(update.case._doc))
    case._id = _map_id(case._id, factor)
    for index in case.indices:
        index.referenced_id = _map_id(index.referenced_id, factor)
    case.name = '{} ({})'.format(case.name, factor)
    return CaseSyncUpdate(case, update.sync_token, required_updates=update.required_updates)


class CaseSyncUpdate(object):
    """
    The record of how a case should sync
    """
    def __init__(self, case, sync_token, required_updates=None):
        self.case = case
        self.sync_token = sync_token
        # cache this property since computing it can be expensive
        self.required_updates = required_updates if required_updates is not None else self._get_required_updates()

    def _get_required_updates(self):
        """
        Returns a list of the required updates for this case/token
        pairing. Should be a list of actions like [create, update, close]
        """
        ret = []
        if not self.sync_token or not self.sync_token.phone_has_case(self.case.get_id):
            ret.append(const.CASE_ACTION_CREATE)
        # always include an update
        ret.append(const.CASE_ACTION_UPDATE)
        if self.case.closed:
            ret.append(const.CASE_ACTION_CLOSE)
        return ret


class GlobalSyncState(object):
    """
    Object containing global state for a BatchedCaseSyncOperation.

    Used within the batches to ensure uniqueness of cases being synced.

    Also used after the sync is complete to provide list of CaseState objects
    """
    def __init__(self, last_sync, case_sharing=False):
{'fraction_non_alphanumeric': 0.07128136743847739, 'fraction_numerical': 0.0014547217844587223, 'mean_word_length': 3.7169811320754715, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 16}, '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': '830435', 'n_tokens_mistral': 2416, 'n_tokens_neox': 2359, 'n_words': 634}