def create_byte(self, last, byte_value):
        words = []
        # Do we need to use a long value or can we use a short value
        if len(self.raw_scores[last].items()) < 256:
            # It is feasible to fail to find a valid result, generally we just need to try again though
            try_again = True
            attempts = 0
            while try_again:
                try:
                    # We start with last in our word list since we care about the transition between words, not words
                    words_to_use = [last]

                    # Since we can potentially spread the value over various word transitions, we maintain a remaining
                    # value left to represent
                    remaining_value = byte_value

                    # Loop until we have our words, or we crap out
                    while True:
                        count = 0

                        # Get the total possibility count, the total needs to be over 256 to possibly represent our byte
                        for word in words_to_use:
                            count += len(self.raw_scores[word].items())

                        if count < 256:
                            # we need another word
                            current_list = sorted(
                                self.raw_scores[words_to_use[-1]].items(),
                                key=operator.itemgetter(1)
                            )[::-1]

                            # we need whichever is smaller, the remaining value or
                            # the length of values for the next word
                            upper_bound = remaining_value if remaining_value < len(current_list) - 1 else len(
                                current_list) - 1

                            # Pick a random word that does not result in us going over our remaining value
                            if upper_bound == 0:
                                index = 0
                            else:
                                index = random.randint(0, upper_bound)

                            # Decrement remaining value and push our word to our list of words
                            remaining_value -= index
                            words_to_use.append(current_list[index][0])
                        else:
                            # We have enough words
                            current_list = sorted(
                                self.raw_scores[words_to_use[-1]].items(),
                                key=operator.itemgetter(1)
                            )[::-1]

                            # If this is true, the algo has failed going down this random path
                            if len(current_list) < remaining_value + 1:
                                raise AlgorithmFailException()

                            # Push our most common last word to terminate our long value
                            words_to_use.append(current_list[remaining_value][0])

                            # Clean out the "last" argument from list
                            words = words_to_use[1:]
                            try_again = False
                            break
                except AlgorithmFailException:
                    try_again = True
                    attempts += 1
                    if attempts > 1024:
                        # shit...
                        #logging.debug("Algorithm failure resistance is failing...rage")
                        #logging.debug("words_to_use: {0}".format(words_to_use))
                        #logging.debug("remaining_value: {0}".format(remaining_value))
                        #logging.debug("last: {0}".format(last))
                        #logging.debug("byte_value: {0}".format(byte_value))
                        #logging.debug("current_list: {0}".format(current_list))
                        raise AlgorithmFailException()
        else:
            # w00t, we can use a short value!
            words.append(sorted(self.raw_scores[last].items(), key=operator.itemgetter(1))[::-1][byte_value][0])

        return words
Captures attributes from an NDB property to be passed to a ProtoRPC field.
dataset/ETHPy150Open bwall/markovobfuscate/markovobfuscate/obfuscation.py/MarkovKeyState.create_byte--crossover with--dataset/ETHPy150Open GoogleCloudPlatform/endpoints-proto-datastore/endpoints_proto_datastore/ndb/utils.py/GetKeywordArgs