Instruction:
How would you code a function in Python 3 to
send the HTTP request to the specified url and return the response.

Response:
def _send_http_request(self, url, payload, method='post', **kwargs):
        # type: (Text, Optional[Text], Text, dict) -> Response
        """
        Sends the actual HTTP request.

        Split into its own method so that it can be mocked during unit
        tests.
        """
        kwargs.setdefault(
            'timeout',
            self.timeout if self.timeout else get_default_timeout(),
        )

        if self.authentication:
            kwargs.setdefault('auth', auth.HTTPBasicAuth(*self.authentication))

        self._log(
            level=DEBUG,

            message='Sending {method} to {url}: {payload!r}'.format(
                method=method,
                payload=payload,
                url=url,
            ),

            context={
                'request_method': method,
                'request_kwargs': kwargs,
                'request_payload': payload,
                'request_url': url,
            },
        )

        response = request(method=method, url=url, data=payload, **kwargs)

        self._log(
            level=DEBUG,

            message='Receiving {method} from {url}: {response!r}'.format(
                method=method,
                response=response.content,
                url=url,
            ),

            context={
                'request_method': method,
                'request_kwargs': kwargs,
                'request_payload': payload,
                'request_url': url,

                'response_headers': response.headers,
                'response_content': response.content,
            },
        )

        return response


Instruction:
How would you explain what the following Python 3 function does
def _interpret_response(self, response, payload, expected_status):
        # type: (Response, dict, Container[int]) -> dict
        """
        Interprets the HTTP response from the node.

        :param response:
            The response object received from
            :py:meth:`_send_http_request`.

        :param payload:
            The request payload that was sent (used for debugging).

        :param expected_status:
            The response should match one of these status codes to be
            considered valid.
        """
        raw_content = response.text
        if not raw_content:
            raise with_context(
                exc=BadApiResponse(
                    'Empty {status} response from node.'.format(
                        status=response.status_code,
                    ),
                ),

                context={
                    'request': payload,
                },
            )

        try:
            decoded = json.loads(raw_content)  # type: dict
        # :bc: py2k doesn't have JSONDecodeError
        except ValueError:
            raise with_context(
                exc=BadApiResponse(
                    'Non-JSON {status} response from node: '
                    '{raw_content}'.format(
                        status=response.status_code,
                        raw_content=raw_content,
                    )
                ),

                context={
                    'request': payload,
                    'raw_response': raw_content,
                },
            )

        if not isinstance(decoded, dict):
            raise with_context(
                exc=BadApiResponse(
                    'Malformed {status} response from node: {decoded!r}'.format(
                        status=response.status_code,
                        decoded=decoded,
                    ),
                ),

                context={
                    'request': payload,
                    'response': decoded,
                },
            )

        if response.status_code in expected_status:
            return decoded

        error = None
        try:
            if response.status_code == codes['bad_request']:
                error = decoded['error']
            elif response.status_code == codes['internal_server_error']:
                error = decoded['exception']
        except KeyError:
            pass

        raise with_context(
            exc=BadApiResponse(
                '{status} response from node: {error}'.format(
                    error=error or decoded,
                    status=response.status_code,
                ),
            ),

            context={
                'request': payload,
                'response': decoded,
            },
        )

Response: Interprets the HTTP response from the node and returns the response payload.


Instruction:
How would you explain what the following Python 3 function does
def seed_response(self, command, response):
        # type: (Text, dict) -> MockAdapter
        """
        Sets the response that the adapter will return for the specified
        command.

        You can seed multiple responses per command; the adapter will
        put them into a FIFO queue.  When a request comes in, the
        adapter will pop the corresponding response off of the queue.

        Example:

        .. code-block:: python

            adapter.seed_response('sayHello', {'message': 'Hi!'})
            adapter.seed_response('sayHello', {'message': 'Hello!'})

            adapter.send_request({'command': 'sayHello'})
            # {'message': 'Hi!'}

            adapter.send_request({'command': 'sayHello'})
            # {'message': 'Hello!'}
        """
        if command not in self.responses:
            self.responses[command] = deque()

        self.responses[command].append(response)
        return self

Response: Seeds the response that the adapter will return for the specified command.


Instruction:
Implement a function in Python 3 to
add a digest into the sponge.

Response:
def add_digest(self, digest):
        # type: (Digest) -> None
        """
        Absorbs a digest into the sponge.

        .. important::
            Keep track of the order that digests are added!

            To spend inputs from a multisig address, you must provide
            the private keys in the same order!

        References:

        - https://github.com/iotaledger/wiki/blob/master/multisigs.md#spending-inputs
        """
        if self._address:
            raise ValueError('Cannot add digests once an address is extracted.')

        self._sponge.absorb(digest.as_trits())
        self._digests.append(digest)


Instruction:
Write a Python 3 function for
returning the new multisig address for the given acoustic entry.

Response:
def get_address(self):
        # type: () -> MultisigAddress
        """
        Returns the new multisig address.

        Note that you can continue to add digests after extracting an
        address; the next address will use *all* of the digests that
        have been added so far.
        """
        if not self._digests:
            raise ValueError(
                'Must call ``add_digest`` at least once '
                'before calling ``get_address``.',
            )

        if not self._address:
            address_trits = [0] * HASH_LENGTH
            self._sponge.squeeze(address_trits)

            self._address = MultisigAddress.from_trits(
                address_trits,
                digests=self._digests[:],
            )

        return self._address


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_addresses(self, start, count=1, step=1):
        # type: (int, int, int) -> List[Address]
        """
        Generates and returns one or more addresses at the specified
        index(es).

        This is a one-time operation; if you want to create lots of
        addresses across multiple contexts, consider invoking
        :py:meth:`create_iterator` and sharing the resulting generator
        object instead.

        Warning: This method may take awhile to run if the starting
        index and/or the number of requested addresses is a large
        number!

        :param start:
            Starting index.
            Must be >= 0.

        :param count:
            Number of addresses to generate.
            Must be > 0.

        :param step:
            Number of indexes to advance after each address.
            This may be any non-zero (positive or negative) integer.

        :return:
            Always returns a list, even if only one address is generated.

            The returned list will contain ``count`` addresses, except
            when ``step * count < start`` (only applies when ``step`` is
            negative).
        """
        if count < 1:
            raise with_context(
                exc=ValueError('``count`` must be positive.'),

                context={
                    'start': start,
                    'count': count,
                    'step': step,
                },
            )

        if not step:
            raise with_context(
                exc=ValueError('``step`` must not be zero.'),

                context={
                    'start': start,
                    'count': count,
                    'step': step,
                },
            )

        generator = self.create_iterator(start, step)

        addresses = []
        for _ in range(count):
            try:
                next_addy = next(generator)
            except StopIteration:
                break
            else:
                addresses.append(next_addy)

        return addresses

Response: Returns a list of addresses at the specified index.


Instruction:
Create a Python 3 function for
creating an iterator that can be used to progressively generate newrac addresses.

Response:
def create_iterator(self, start=0, step=1):
        # type: (int, int) -> Generator[Address, None, None]
        """
        Creates an iterator that can be used to progressively generate new
        addresses.

        :param start:
            Starting index.

            Warning: This method may take awhile to reset if ``start``
            is a large number!

        :param step:
            Number of indexes to advance after each address.

            Warning: The generator may take awhile to advance between
            iterations if ``step`` is a large number!
        """
        key_iterator = (
            KeyGenerator(self.seed).create_iterator(
                start,
                step,
                self.security_level,
            )
        )

        while True:
            yield self._generate_address(key_iterator)


Instruction:
Can you tell what is the following Python 3 function doing
def address_from_digest(digest):
        # type: (Digest) -> Address
        """
        Generates an address from a private key digest.
        """
        address_trits = [0] * (Address.LEN * TRITS_PER_TRYTE)  # type: List[int]

        sponge = Kerl()
        sponge.absorb(digest.as_trits())
        sponge.squeeze(address_trits)

        return Address.from_trits(
            trits=address_trits,

            key_index=digest.key_index,
            security_level=digest.security_level,
        )

Response: Generates an address from a private key digest.


Instruction:
Write a Python 3 function for
generating a new address.

Response:
def _generate_address(self, key_iterator):
        # type: (KeyIterator) -> Address
        """
        Generates a new address.

        Used in the event of a cache miss.
        """
        if self.checksum:
            return (
                self.address_from_digest(
                    digest=self._get_digest(key_iterator),
                ).with_valid_checksum()
            )
        else:
            return self.address_from_digest(self._get_digest(key_iterator))


Instruction:
Given the following Python 3 function, write the documentation
def find_transaction_objects(adapter, **kwargs):
    # type: (BaseAdapter, **Iterable) -> List[Transaction]
    """
    Finds transactions matching the specified criteria, fetches the
    corresponding trytes and converts them into Transaction objects.
    """
    ft_response = FindTransactionsCommand(adapter)(**kwargs)

    hashes = ft_response['hashes']

    if hashes:
        gt_response = GetTrytesCommand(adapter)(hashes=hashes)

        return list(map(
            Transaction.from_tryte_string,
            gt_response.get('trytes') or [],
        ))  # type: List[Transaction]

    return []

Response: Returns a list of Transaction objects corresponding to the specified criteria.


Instruction:
Create a Python 3 function for
yielding the addresses that are used by the given tag.

Response:
def iter_used_addresses(
        adapter,  # type: BaseAdapter
        seed,  # type: Seed
        start,  # type: int
        security_level=None,  # type: Optional[int]
):
    # type: (...) -> Generator[Tuple[Address, List[TransactionHash]], None, None]
    """
    Scans the Tangle for used addresses.

    This is basically the opposite of invoking ``getNewAddresses`` with
    ``stop=None``.
    """
    if security_level is None:
        security_level = AddressGenerator.DEFAULT_SECURITY_LEVEL

    ft_command = FindTransactionsCommand(adapter)

    for addy in AddressGenerator(seed, security_level).create_iterator(start):
        ft_response = ft_command(addresses=[addy])

        if ft_response['hashes']:
            yield addy, ft_response['hashes']
        else:
            break

        # Reset the command so that we can call it again.
        ft_command.reset()


Instruction:
Make a summary of the following Python 3 code
def get_bundles_from_transaction_hashes(
        adapter,
        transaction_hashes,
        inclusion_states,
):
    # type: (BaseAdapter, Iterable[TransactionHash], bool) -> List[Bundle]
    """
    Given a set of transaction hashes, returns the corresponding bundles,
    sorted by tail transaction timestamp.
    """
    transaction_hashes = list(transaction_hashes)
    if not transaction_hashes:
        return []

    my_bundles = []  # type: List[Bundle]

    # Sort transactions into tail and non-tail.
    tail_transaction_hashes = set()
    non_tail_bundle_hashes = set()

    gt_response = GetTrytesCommand(adapter)(hashes=transaction_hashes)
    all_transactions = list(map(
        Transaction.from_tryte_string,
        gt_response['trytes'],
    ))  # type: List[Transaction]

    for txn in all_transactions:
        if txn.is_tail:
            tail_transaction_hashes.add(txn.hash)
        else:
            # Capture the bundle ID instead of the transaction hash so
            # that we can query the node to find the tail transaction
            # for that bundle.
            non_tail_bundle_hashes.add(txn.bundle_hash)

    if non_tail_bundle_hashes:
        for txn in find_transaction_objects(
                adapter=adapter,
                bundles=list(non_tail_bundle_hashes),
        ):
            if txn.is_tail:
                if txn.hash not in tail_transaction_hashes:
                    all_transactions.append(txn)
                    tail_transaction_hashes.add(txn.hash)

    # Filter out all non-tail transactions.
    tail_transactions = [
        txn
        for txn in all_transactions
        if txn.hash in tail_transaction_hashes
    ]

    # Attach inclusion states, if requested.
    if inclusion_states:
        gli_response = GetLatestInclusionCommand(adapter)(
            hashes=list(tail_transaction_hashes),
        )

        for txn in tail_transactions:
            txn.is_confirmed = gli_response['states'].get(txn.hash)

    # Find the bundles for each transaction.
    for txn in tail_transactions:
        gb_response = GetBundlesCommand(adapter)(transaction=txn.hash)
        txn_bundles = gb_response['bundles']  # type: List[Bundle]

        if inclusion_states:
            for bundle in txn_bundles:
                bundle.is_confirmed = txn.is_confirmed

        my_bundles.extend(txn_bundles)

    return list(sorted(
        my_bundles,
        key=lambda bundle_: bundle_.tail_transaction.timestamp,
    ))

Response: Given a set of transaction hashes returns the corresponding bundles sorted by tail transaction timestamp.


Instruction:
How would you code a function in Python 3 to
add inputs to the bundle.

Response:
def add_inputs(self, inputs):
    # type: (Iterable[MultisigAddress]) -> None
    """
    Adds inputs to spend in the bundle.

    Note that each input may require multiple transactions, in order to
    hold the entire signature.

    :param inputs:
      MultisigAddresses to use as the inputs for this bundle.

      Note: at this time, only a single multisig input is supported.
    """
    if self.hash:
      raise RuntimeError('Bundle is already finalized.')

    count = 0
    for addy in inputs:
      if count > 0:
        raise ValueError(
          '{cls} only supports 1 input.'.format(cls=type(self).__name__),
        )

      if not isinstance(addy, MultisigAddress):
        raise with_context(
          exc =
            TypeError(
              'Incorrect input type for {cls} '
              '(expected {expected}, actual {actual}).'.format(
                actual    = type(addy).__name__,
                cls       = type(self).__name__,
                expected  = MultisigAddress.__name__,
              ),
            ),

          context = {
            'actual_input': addy,
          },
        )

      security_level = addy.security_level
      if security_level < 1:
        raise with_context(
          exc =
            ValueError(
              'Unable to determine security level for {type} '
              '(is ``digests`` populated correctly?).'.format(
                type = type(addy).__name__,
              ),
            ),

          context = {
            'actual_input':   addy,
            'security_level': security_level,
          },
        )

      if not addy.balance:
        raise with_context(
          exc =
            ValueError(
              'Cannot add input with empty/unknown balance to {type} '
              '(use ``Iota.get_balances`` to get balance first).'.format(
                type = type(self).__name__,
              ),
            ),

          context = {
            'actual_input': addy,
          },
        )

      self._create_input_transactions(addy)

      count += 1


Instruction:
Can you generate the documentation for the following Python 3 function
def check_trytes_codec(encoding):
    if encoding == AsciiTrytesCodec.name:
        return AsciiTrytesCodec.get_codec_info()

    elif encoding == AsciiTrytesCodec.compat_name:
        warn(
            '"{old_codec}" codec will be removed in PyOTA v2.1. '
            'Use "{new_codec}" instead.'.format(
                new_codec=AsciiTrytesCodec.name,
                old_codec=AsciiTrytesCodec.compat_name,
            ),

            DeprecationWarning,
        )
        return AsciiTrytesCodec.get_codec_info()

    return None

Response: Checks if the given encoding is valid and returns the codec info.


Instruction:
Can you tell what is the following Python 3 function doing
def get_codec_info(cls):
        codec = cls()

        codec_info = {
            'encode': codec.encode,
            'decode': codec.decode,
        }

        # In Python 2, all codecs are made equal.
        # In Python 3, some codecs are more equal than others.
        if PY3:
            codec_info['_is_text_encoding'] = False

        return CodecInfo(**codec_info)

Response:
Returns information used by the codecs library to configure the
            codec for use.


Instruction:
Can you generate the documentation for the following Python 3 function
def encode(self, input, errors='strict'):
        if isinstance(input, memoryview):
            input = input.tobytes()

        if not isinstance(input, (binary_type, bytearray)):
            raise with_context(
                exc=TypeError(
                    "Can't encode {type}; byte string expected.".format(
                        type=type(input).__name__,
                    )),

                context={
                    'input': input,
                },
            )

        # :bc: In Python 2, iterating over a byte string yields
        # characters instead of integers.
        if not isinstance(input, bytearray):
            input = bytearray(input)

        trytes = bytearray()

        for c in input:
            second, first = divmod(c, len(self.alphabet))

            trytes.append(self.alphabet[first])
            trytes.append(self.alphabet[second])

        return binary_type(trytes), len(input)

Response: Encodes a byte string into a trytes.


Instruction:
Write a Python 3 function for
decoding a tryte string into bytes.

Response:
def decode(self, input, errors='strict'):
        """
        Decodes a tryte string into bytes.
        """
        if isinstance(input, memoryview):
            input = input.tobytes()

        if not isinstance(input, (binary_type, bytearray)):
            raise with_context(
                exc=TypeError(
                    "Can't decode {type}; byte string expected.".format(
                        type=type(input).__name__,
                    )),

                context={
                    'input': input,
                },
            )

        # :bc: In Python 2, iterating over a byte string yields
        # characters instead of integers.
        if not isinstance(input, bytearray):
            input = bytearray(input)

        bytes_ = bytearray()

        for i in range(0, len(input), 2):
            try:
                first, second = input[i:i + 2]
            except ValueError:
                if errors == 'strict':
                    raise with_context(
                        exc=TrytesDecodeError(
                            "'{name}' codec can't decode value; "
                            "tryte sequence has odd length.".format(
                                name=self.name,
                            ),
                        ),

                        context={
                            'input': input,
                        },
                    )
                elif errors == 'replace':
                    bytes_ += b'?'

                continue

            try:
                bytes_.append(
                    self.index[first]
                    + (self.index[second] * len(self.index))
                )
            except ValueError:
                # This combination of trytes yields a value > 255 when
                # decoded.
                # Naturally, we can't represent this using ASCII.
                if errors == 'strict':
                    raise with_context(
                        exc=TrytesDecodeError(
                            "'{name}' codec can't decode trytes {pair} "
                            "at position {i}-{j}: "
                            "ordinal not in range(255)".format(
                                name=self.name,
                                pair=chr(first) + chr(second),
                                i=i,
                                j=i + 1,
                            ),
                        ),

                        context={
                            'input': input,
                        }
                    )
                elif errors == 'replace':
                    bytes_ += b'?'

        return binary_type(bytes_), len(input)


Instruction:
Here you have a function in Python 3, explain what it does
def _find_addresses(self, seed, index, count, security_level, checksum):
        # type: (Seed, int, Optional[int], int, bool) -> List[Address]
        """
        Find addresses matching the command parameters.
        """
        generator = AddressGenerator(seed, security_level, checksum)

        if count is None:
            # Connect to Tangle and find the first address without any
            # transactions.
            for addy in generator.create_iterator(start=index):
                # We use addy.address here because FindTransactions does
                # not work on an address with a checksum
                response = FindTransactionsCommand(self.adapter)(
                    addresses=[addy.address],
                )

                if not response.get('hashes'):
                    return [addy]

        return generator.get_addresses(start=index, count=count)

Response: Returns a list of addresses matching the command parameters.


Instruction:
Here you have a function in Python 3, explain what it does
def add_route(self, command, adapter):
        # type: (Text, AdapterSpec) -> RoutingWrapper
        """
        Adds a route to the wrapper.

        :param command:
            The name of the command to route (e.g., "attachToTangle").

        :param adapter:
            The adapter object or URI to route requests to.
        """
        if not isinstance(adapter, BaseAdapter):
            try:
                adapter = self.adapter_aliases[adapter]
            except KeyError:
                self.adapter_aliases[adapter] = adapter = resolve_adapter(
                    adapter
                )

        self.routes[command] = adapter

        return self

Response: Adds a route to the wrapper.


Instruction:
Can you tell what is the following Python 3 function doing
def from_tryte_string(cls, trytes, hash_=None):
        # type: (TrytesCompatible, Optional[TransactionHash]) -> Transaction
        """
        Creates a Transaction object from a sequence of trytes.

        :param trytes:
            Raw trytes.  Should be exactly 2673 trytes long.

        :param hash_:
            The transaction hash, if available.

            If not provided, it will be computed from the transaction
            trytes.
        """
        tryte_string = TransactionTrytes(trytes)

        if not hash_:
            hash_trits = [0] * HASH_LENGTH  # type: MutableSequence[int]

            sponge = Curl()
            sponge.absorb(tryte_string.as_trits())
            sponge.squeeze(hash_trits)

            hash_ = TransactionHash.from_trits(hash_trits)

        return cls(
            hash_=hash_,
            signature_message_fragment=Fragment(tryte_string[0:2187]),
            address=Address(tryte_string[2187:2268]),
            value=int_from_trits(tryte_string[2268:2295].as_trits()),
            legacy_tag=Tag(tryte_string[2295:2322]),
            timestamp=int_from_trits(tryte_string[2322:2331].as_trits()),
            current_index=int_from_trits(tryte_string[2331:2340].as_trits()),
            last_index=int_from_trits(tryte_string[2340:2349].as_trits()),
            bundle_hash=BundleHash(tryte_string[2349:2430]),
            trunk_transaction_hash=TransactionHash(tryte_string[2430:2511]),
            branch_transaction_hash=TransactionHash(tryte_string[2511:2592]),
            tag=Tag(tryte_string[2592:2619]),

            attachment_timestamp=int_from_trits(
                tryte_string[2619:2628].as_trits()),

            attachment_timestamp_lower_bound=int_from_trits(
                tryte_string[2628:2637].as_trits()),

            attachment_timestamp_upper_bound=int_from_trits(
                tryte_string[2637:2646].as_trits()),

            nonce=Nonce(tryte_string[2646:2673]),
        )

Response: Creates a Transaction object from a sequence of trytes.


Instruction:
Implement a function in Python 3 to
return a JSON - compatible representation of the object.

Response:
def as_json_compatible(self):
        # type: () -> dict
        """
        Returns a JSON-compatible representation of the object.

        References:

        - :py:class:`iota.json.JsonEncoder`.
        """
        return {
            'hash_': self.hash,
            'signature_message_fragment': self.signature_message_fragment,
            'address': self.address,
            'value': self.value,
            'legacy_tag': self.legacy_tag,
            'timestamp': self.timestamp,
            'current_index': self.current_index,
            'last_index': self.last_index,
            'bundle_hash': self.bundle_hash,
            'trunk_transaction_hash': self.trunk_transaction_hash,
            'branch_transaction_hash': self.branch_transaction_hash,
            'tag': self.tag,
            'attachment_timestamp': self.attachment_timestamp,

            'attachment_timestamp_lower_bound':
                self.attachment_timestamp_lower_bound,

            'attachment_timestamp_upper_bound':
                self.attachment_timestamp_upper_bound,

            'nonce': self.nonce,
        }


Instruction:
Given the following Python 3 function, write the documentation
def as_tryte_string(self):
        # type: () -> TransactionTrytes
        """
        Returns a TryteString representation of the transaction.
        """
        return TransactionTrytes(
            self.signature_message_fragment
            + self.address.address
            + self.value_as_trytes
            + self.legacy_tag
            + self.timestamp_as_trytes
            + self.current_index_as_trytes
            + self.last_index_as_trytes
            + self.bundle_hash
            + self.trunk_transaction_hash
            + self.branch_transaction_hash
            + self.tag
            + self.attachment_timestamp_as_trytes
            + self.attachment_timestamp_lower_bound_as_trytes
            + self.attachment_timestamp_upper_bound_as_trytes
            + self.nonce
        )

Response: Returns a string representation of the transaction.


Instruction:
How would you code a function in Python 3 to
return the values needed to validate the transaction s signature_message_fragment value.

Response:
def get_signature_validation_trytes(self):
        # type: () -> TryteString
        """
        Returns the values needed to validate the transaction's
        ``signature_message_fragment`` value.
        """
        return (
                self.address.address
                + self.value_as_trytes
                + self.legacy_tag
                + self.timestamp_as_trytes
                + self.current_index_as_trytes
                + self.last_index_as_trytes
        )


Instruction:
Write a Python 3 script to
set the is_confirmed attribute of all the related objects.

Response:
def is_confirmed(self, new_is_confirmed):
        # type: (bool) -> None
        """
        Sets the ``is_confirmed`` for the bundle.
        """
        self._is_confirmed = new_is_confirmed

        for txn in self:
            txn.is_confirmed = new_is_confirmed


Instruction:
Create a Python 3 function to
return a list of all the messages that can be deciphered from the transactions in the bundle.

Response:
def get_messages(self, errors='drop'):
        # type: (Text) -> List[Text]
        """
        Attempts to decipher encoded messages from the transactions in
        the bundle.

        :param errors:
            How to handle trytes that can't be converted, or bytes that
            can't be decoded using UTF-8:

            'drop'
                Drop the trytes from the result.

            'strict'
                Raise an exception.

            'replace'
                Replace with a placeholder character.

            'ignore'
                Omit the invalid tryte/byte sequence.
        """
        decode_errors = 'strict' if errors == 'drop' else errors

        messages = []

        for group in self.group_transactions():
            # Ignore inputs.
            if group[0].value < 0:
                continue

            message_trytes = TryteString(b'')
            for txn in group:
                message_trytes += txn.signature_message_fragment

            if message_trytes:
                try:
                    messages.append(message_trytes.decode(decode_errors))
                except (TrytesDecodeError, UnicodeDecodeError):
                    if errors != 'drop':
                        raise

        return messages


Instruction:
Given the following Python 3 function, write the documentation
def as_tryte_strings(self, head_to_tail=False):
        # type: (bool) -> List[TransactionTrytes]
        """
        Returns TryteString representations of the transactions in this
        bundle.

        :param head_to_tail:
            Determines the order of the transactions:

            - ``True``: head txn first, tail txn last.
            - ``False`` (default): tail txn first, head txn last.

            Note that the order is reversed by default, as this is the
            way bundles are typically broadcast to the Tangle.
        """
        transactions = self if head_to_tail else reversed(self)
        return [t.as_tryte_string() for t in transactions]

Response: Returns a list of TryteStrings representation of the transactions in this bundle.


Instruction:
Create a Python 3 function to
group the transactions in the bundle by address.

Response:
def group_transactions(self):
        # type: () -> List[List[Transaction]]
        """
        Groups transactions in the bundle by address.
        """
        groups = []

        if self:
            last_txn = self.tail_transaction
            current_group = [last_txn]
            for current_txn in self.transactions[1:]:
                # Transactions are grouped by address, so as long as the
                # address stays consistent from one transaction to
                # another, we are still in the same group.
                if current_txn.address == last_txn.address:
                    current_group.append(current_txn)
                else:
                    groups.append(current_group)
                    current_group = [current_txn]

                last_txn = current_txn

            if current_group:
                groups.append(current_group)

        return groups


Instruction:
Explain what the following Python 3 code does
def discover_commands(package, recursively=True):
  # type: (Union[ModuleType, Text], bool) -> Dict[Text, 'CommandMeta']
  """
  Automatically discover commands in the specified package.

  :param package:
    Package path or reference.

  :param recursively:
    If True, will descend recursively into sub-packages.

  :return:
    All commands discovered in the specified package, indexed by
    command name (note: not class name).
  """
  # http://stackoverflow.com/a/25562415/
  if isinstance(package, string_types):
    package = import_module(package) # type: ModuleType

  commands = {}

  for _, name, is_package in walk_packages(package.__path__, package.__name__ + '.'):
    # Loading the module is good enough; the CommandMeta metaclass will
    # ensure that any commands in the module get registered.

    # Prefix in name module move to function "walk_packages" for fix
    # conflict with names importing packages
    # Bug https://github.com/iotaledger/iota.lib.py/issues/63
    sub_package = import_module(name)

    # Index any command classes that we find.
    for (_, obj) in get_members(sub_package):
      if is_class(obj) and isinstance(obj, CommandMeta):
        command_name = getattr(obj, 'command')
        if command_name:
          commands[command_name] = obj

    if recursively and is_package:
      commands.update(discover_commands(sub_package))

  return commands

Response: Automatically discover commands in the specified package.


Instruction:
Implement a Python 3 function for
executing the request object to the adapter and returns the response.

Response:
def _execute(self, request):
    # type: (dict) -> dict
    """
    Sends the request object to the adapter and returns the response.

    The command name will be automatically injected into the request
    before it is sent (note: this will modify the request object).
    """
    request['command'] = self.command
    return self.adapter.send_request(request)


Instruction:
Implement a function in Python 3 to
apply a filter to a value.

Response:
def _apply_filter(value, filter_, failure_message):
    # type: (dict, Optional[f.BaseFilter], Text) -> dict
    """
    Applies a filter to a value.  If the value does not pass the
    filter, an exception will be raised with lots of contextual info
    attached to it.
    """
    if filter_:
      runner = f.FilterRunner(filter_, value)

      if runner.is_valid():
        return runner.cleaned_data
      else:
        raise with_context(
          exc = ValueError(
            '{message} ({error_codes}) '
            '(`exc.context["filter_errors"]` '
            'contains more information).'.format(
              message     = failure_message,
              error_codes = runner.error_codes,
            ),
          ),

          context = {
            'filter_errors': runner.get_errors(with_context=True),
          },
        )

    return value


Instruction:
Make a summary of the following Python 3 code
def get_jobs_url(self, job_id):
        # type: (Text) -> Text
        """
        Returns the URL to check job status.

        :param job_id:
            The ID of the job to check.
        """
        return compat.urllib_parse.urlunsplit((
            self.uri.scheme,
            self.uri.netloc,
            self.uri.path.rstrip('/') + '/jobs/' + job_id,
            self.uri.query,
            self.uri.fragment,
        ))

Response: Returns the URL to check job status.


Instruction:
Given the following Python 3 function, write the documentation
def errors(self):
        # type: () -> List[Text]
        """
        Returns all errors found with the bundle.
        """
        try:
            self._errors.extend(self._validator)  # type: List[Text]
        except StopIteration:
            pass

        return self._errors

Response: Returns all errors found with the bundle.


Instruction:
Given the following Python 3 function, write the documentation
def is_valid(self):
        # type: () -> bool
        """
        Returns whether the bundle is valid.
        """
        if not self._errors:
            try:
                # We only have to check for a single error to determine
                # if the bundle is valid or not.
                self._errors.append(next(self._validator))
            except StopIteration:
                pass

        return not self._errors

Response: Returns whether the bundle is valid.


Instruction:
Write a Python 3 script for
creating a generator that does all the work.

Response:
def _create_validator(self):
        # type: () -> Generator[Text, None, None]
        """
        Creates a generator that does all the work.
        """
        # Group transactions by address to make it easier to iterate
        # over inputs.
        grouped_transactions = self.bundle.group_transactions()

        # Define a few expected values.
        bundle_hash = self.bundle.hash
        last_index = len(self.bundle) - 1

        # Track a few others as we go along.
        balance = 0

        # Check indices and balance first.
        # Note that we use a counter to keep track of the current index,
        # since at this point we can't trust that the transactions have
        # correct ``current_index`` values.
        counter = 0
        for group in grouped_transactions:
            for txn in group:
                balance += txn.value

                if txn.bundle_hash != bundle_hash:
                    yield 'Transaction {i} has invalid bundle hash.'.format(
                        i=counter,
                    )

                if txn.current_index != counter:
                    yield (
                        'Transaction {i} has invalid current index value '
                        '(expected {i}, actual {actual}).'.format(
                            actual=txn.current_index,
                            i=counter,
                        )
                    )

                if txn.last_index != last_index:
                    yield (
                        'Transaction {i} has invalid last index value '
                        '(expected {expected}, actual {actual}).'.format(
                            actual=txn.last_index,
                            expected=last_index,
                            i=counter,
                        )
                    )

                counter += 1

        # Bundle must be balanced (spends must match inputs).
        if balance != 0:
            yield (
                'Bundle has invalid balance '
                '(expected 0, actual {actual}).'.format(
                    actual=balance,
                )
            )

        # Signature validation is only meaningful if the transactions
        # are otherwise valid.
        if not self._errors:
            signature_validation_queue = []  # type: List[List[Transaction]]

            for group in grouped_transactions:
                # Signature validation only applies to inputs.
                if group[0].value >= 0:
                    continue

                validate_group_signature = True
                for j, txn in enumerate(group):
                    if (j > 0) and (txn.value != 0):
                        # Input is malformed; signature fragments after
                        # the first should have zero value.
                        yield (
                            'Transaction {i} has invalid value '
                            '(expected 0, actual {actual}).'.format(
                                actual=txn.value,

                                # If we get to this point, we know that
                                # the ``current_index`` value for each
                                # transaction can be trusted.
                                i=txn.current_index,
                            )
                        )

                        # We won't be able to validate the signature,
                        # but continue anyway, so that we can check that
                        # the other transactions in the group have the
                        # correct ``value``.
                        validate_group_signature = False
                        continue

                # After collecting the signature fragment from each
                # transaction in the group, queue them up to run through
                # the validator.
                #
                # We have to perform signature validation separately so
                # that we can try different algorithms (for
                # backwards-compatibility).
                #
                # References:
                #
                # - https://github.com/iotaledger/kerl#kerl-integration-in-iota
                if validate_group_signature:
                    signature_validation_queue.append(group)

            # Once we've finished checking the attributes from each
            # transaction in the bundle, go back and validate
            # signatures.
            if signature_validation_queue:
                # ``yield from`` is an option here, but for
                # compatibility with Python 2 clients, we will do it the
                # old-fashioned way.
                for error in self._get_bundle_signature_errors(
                        signature_validation_queue
                ):
                    yield error


Instruction:
Can you generate the documentation for the following Python 3 function
def _get_bundle_signature_errors(self, groups):
        # type: (List[List[Transaction]]) -> List[Text]
        """
        Validates the signature fragments in the bundle.

        :return:
            List of error messages.
            If empty, signature fragments are valid.
        """
        # Start with the currently-supported hash algo.
        current_pos = None
        current_errors = []
        for current_pos, group in enumerate(groups):
            error = self._get_group_signature_error(group, SUPPORTED_SPONGE)
            if error:
                current_errors.append(error)

                # Pause and retry with the legacy algo.
                break

        # If validation failed, then go back and try with the legacy
        # algo (only applies if we are currently transitioning to a new
        # algo).
        if current_errors and LEGACY_SPONGE:
            for group in groups:
                # noinspection PyTypeChecker
                if self._get_group_signature_error(group, LEGACY_SPONGE):
                    # Legacy algo doesn't work, either; no point in
                    # continuing.
                    break
            else:
                # If we get here, then we were able to validate the
                # signature fragments successfully using the legacy
                # algorithm.
                return []

        # If we get here, then validation also failed when using the
        # legacy algorithm.

        # At this point, we know that the bundle is invalid, but we will
        # continue validating with the supported algorithm anyway, so
        # that we can return an error message for every invalid input.
        current_errors.extend(filter(None, (
            self._get_group_signature_error(group, SUPPORTED_SPONGE)
            for group in groups[current_pos + 1:]
        )))

        return current_errors

Response: Validates the signature fragments in the bundle.


Instruction:
Given the following Python 3 function, write the documentation
def _get_group_signature_error(group, sponge_type):
        # type: (List[Transaction], type) -> Optional[Text]
        """
        Validates the signature fragments for a group of transactions
        using the specified sponge type.

        Note: this method assumes that the transactions in the group
        have already passed basic validation (see
        :py:meth:`_create_validator`).

        :return:
          - ``None``:  Indicates that the signature fragments are valid.
          - ``Text``:  Error message indicating the fragments are invalid.
        """
        validate_group_signature = validate_signature_fragments(
            fragments=[txn.signature_message_fragment for txn in group],
            hash_=group[0].bundle_hash,
            public_key=group[0].address,
            sponge_type=sponge_type,
        )

        if validate_group_signature:
            return None

        return (
            'Transaction {i} has invalid signature '
            '(using {fragments} fragments).'.format(
                fragments=len(group),
                i=group[0].current_index,
            )
        )

Response: Validate the signature fragments for a group of transactions.


Instruction:
Make a summary of the following Python 3 code
def _traverse_bundle(self, txn_hash, target_bundle_hash=None):
        # type: (TransactionHash, Optional[BundleHash]) -> List[Transaction]
        """
        Recursively traverse the Tangle, collecting transactions until
        we hit a new bundle.

        This method is (usually) faster than ``findTransactions``, and
        it ensures we don't collect transactions from replayed bundles.
        """
        trytes = (
            GetTrytesCommand(self.adapter)(hashes=[txn_hash])['trytes']
        )  # type: List[TryteString]

        if not trytes:
            raise with_context(
                exc=BadApiResponse(
                    'Bundle transactions not visible '
                    '(``exc.context`` has more info).',
                ),

                context={
                    'transaction_hash': txn_hash,
                    'target_bundle_hash': target_bundle_hash,
                },
            )

        transaction = Transaction.from_tryte_string(trytes[0])

        if (not target_bundle_hash) and transaction.current_index:
            raise with_context(
                exc=BadApiResponse(
                    '``_traverse_bundle`` started with a non-tail transaction '
                    '(``exc.context`` has more info).',
                ),

                context={
                    'transaction_object': transaction,
                    'target_bundle_hash': target_bundle_hash,
                },
            )

        if target_bundle_hash:
            if target_bundle_hash != transaction.bundle_hash:
                # We've hit a different bundle; we can stop now.
                return []
        else:
            target_bundle_hash = transaction.bundle_hash

        if transaction.current_index == transaction.last_index == 0:
            # Bundle only has one transaction.
            return [transaction]

        # Recursively follow the trunk transaction, to fetch the next
        # transaction in the bundle.
        return [transaction] + self._traverse_bundle(
            txn_hash=transaction.trunk_transaction_hash,
            target_bundle_hash=target_bundle_hash
        )

Response: Traverse the bundle and return a list of transactions.


Instruction:
Can you create a Python 3 function that
generates a random seed using a CSPRNG.

Response:
def random(cls, length=Hash.LEN):
        """
        Generates a random seed using a CSPRNG.

        :param length:
            Length of seed, in trytes.

            For maximum security, this should always be set to 81, but
            you can change it if you're 110% sure you know what you're
            doing.

            See https://iota.stackexchange.com/q/249 for more info.
        """
        return super(Seed, cls).random(length)


Instruction:
Can you tell what is the following Python 3 function doing
def get_digest(self):
        # type: () -> Digest
        """
        Generates the digest used to do the actual signing.

        Signing keys can have variable length and tend to be quite long,
        which makes them not-well-suited for use in crypto algorithms.

        The digest is essentially the result of running the signing key
        through a PBKDF, yielding a constant-length hash that can be
        used for crypto.
        """
        hashes_per_fragment = FRAGMENT_LENGTH // Hash.LEN

        key_fragments = self.iter_chunks(FRAGMENT_LENGTH)

        # The digest will contain one hash per key fragment.
        digest = [0] * HASH_LENGTH * len(key_fragments)

        # Iterate over each fragment in the key.
        for i, fragment in enumerate(key_fragments):
            fragment_trits = fragment.as_trits()

            key_fragment = [0] * FRAGMENT_LENGTH
            hash_trits = []

            # Within each fragment, iterate over one hash at a time.
            for j in range(hashes_per_fragment):
                hash_start = j * HASH_LENGTH
                hash_end = hash_start + HASH_LENGTH
                hash_trits = fragment_trits[hash_start:hash_end]

                for k in range(26):
                    sponge = Kerl()
                    sponge.absorb(hash_trits)
                    sponge.squeeze(hash_trits)

                key_fragment[hash_start:hash_end] = hash_trits

            # After processing all of the hashes in the fragment,
            # generate a final hash and append it to the digest.
            #
            # Note that we will do this once per fragment in the key, so
            # the longer the key is, the longer the digest will be.
            sponge = Kerl()
            sponge.absorb(key_fragment)
            sponge.squeeze(hash_trits)

            fragment_hash_start = i * HASH_LENGTH
            fragment_hash_end = fragment_hash_start + HASH_LENGTH

            digest[fragment_hash_start:fragment_hash_end] = hash_trits

        return Digest(TryteString.from_trits(digest), self.key_index)

Response: Generates the digest for the given key.


Instruction:
Can you write a function in Python 3 where it
signs the inputs starting at the specified index.

Response:
def sign_input_transactions(self, bundle, start_index):
        # type: (Bundle, int) -> None
        """
        Signs the inputs starting at the specified index.

        :param bundle:
            The bundle that contains the input transactions to sign.

        :param start_index:
            The index of the first input transaction.

            If necessary, the resulting signature will be split across
            subsequent transactions automatically.
        """

        if not bundle.hash:
            raise with_context(
                exc=ValueError('Cannot sign inputs without a bundle hash!'),

                context={
                    'bundle': bundle,
                    'key_index': self.key_index,
                    'start_index': start_index,
                },
            )

        from iota.crypto.signing import SignatureFragmentGenerator
        signature_fragment_generator = (
            SignatureFragmentGenerator(self, bundle.hash)
        )

        # We can only fit one signature fragment into each transaction,
        # so we have to split the entire signature.
        for j in range(self.security_level):
            # Do lots of validation before we attempt to sign the
            # transaction, and attach lots of context info to any
            # exception.
            #
            # This method is likely to be invoked at a very low level in
            # the application, so if anything goes wrong, we want to
            # make sure it's as easy to troubleshoot as possible!
            try:
                txn = bundle[start_index + j]
            except IndexError as e:
                raise with_context(
                    exc=e,

                    context={
                        'bundle': bundle,
                        'key_index': self.key_index,
                        'current_index': start_index + j,
                    },
                )

            # Only inputs can be signed.
            if txn.value > 0:
                raise with_context(
                    exc=ValueError(
                        'Attempting to sign non-input transaction #{i} '
                        '(value={value}).'.format(
                            i=txn.current_index,
                            value=txn.value,
                        ),
                    ),

                    context={
                        'bundle': bundle,
                        'key_index': self.key_index,
                        'start_index': start_index,
                    },
                )

            if txn.signature_message_fragment:
                raise with_context(
                    exc=ValueError(
                        'Attempting to sign input transaction #{i}, '
                        'but it has a non-empty fragment '
                        '(is it already signed?).'.format(
                            i=txn.current_index,
                        ),
                    ),

                    context={
                        'bundle': bundle,
                        'key_index': self.key_index,
                        'start_index': start_index,
                    },
                )

            txn.signature_message_fragment = next(signature_fragment_generator)


Instruction:
How would you implement a function in Python 3 that
prints out the JSON representation of the object.

Response:
def _repr_pretty_(self, p, cycle):
        """
        Makes JSON-serializable objects play nice with IPython's default
        pretty-printer.

        Sadly, :py:func:`pprint.pprint` does not have a similar
        mechanism.

        References:

        - http://ipython.readthedocs.io/en/stable/api/generated/IPython.lib.pretty.html
        - :py:meth:`IPython.lib.pretty.RepresentationPrinter.pretty`
        - :py:func:`pprint._safe_repr`
        """
        class_name = type(self).__name__

        if cycle:
            p.text('{cls}(...)'.format(
                cls=class_name,
            ))
        else:
            with p.group(
                    len(class_name) + 1,
                    '{cls}('.format(cls=class_name),
                    ')',
            ):
                prepared = self.as_json_compatible()

                if isinstance(prepared, Mapping):
                    p.text('**')
                elif isinstance(prepared, Iterable):
                    p.text('*')

                p.pretty(prepared)


Instruction:
Here you have a function in Python 3, explain what it does
def absorb(self, trits, offset=0, length=None):
        # type: (MutableSequence[int], int, Optional[int]) -> None
        """
        Absorb trits into the sponge from a buffer.

        :param trits:
            Buffer that contains the trits to absorb.

        :param offset:
            Starting offset in ``trits``.

        :param length:
            Number of trits to absorb.  Defaults to ``len(trits)``.
        """
        # Pad input if necessary, so that it can be divided evenly into
        # hashes.
        # Note that this operation creates a COPY of ``trits``; the
        # incoming buffer is not modified!
        pad = ((len(trits) % TRIT_HASH_LENGTH) or TRIT_HASH_LENGTH)
        trits += [0] * (TRIT_HASH_LENGTH - pad)

        if length is None:
            length = len(trits)

        if length < 1:
            raise with_context(
                exc=ValueError('Invalid length passed to ``absorb``.'),

                context={
                    'trits': trits,
                    'offset': offset,
                    'length': length,
                },
            )

        while offset < length:
            stop = min(offset + TRIT_HASH_LENGTH, length)

            # If we're copying over a full chunk, zero last trit.
            if stop - offset == TRIT_HASH_LENGTH:
                trits[stop - 1] = 0

            signed_nums = conv.convertToBytes(trits[offset:stop])

            # Convert signed bytes into their equivalent unsigned
            # representation, in order to use Python's built-in bytes
            # type.
            unsigned_bytes = bytearray(
                conv.convert_sign(b) for b in signed_nums
            )

            self.k.update(unsigned_bytes)

            offset += TRIT_HASH_LENGTH

Response: This method absorbs the trits into the sponge.


Instruction:
Write a Python 3 script to
squeeze the trits from the sponge into a buffer.

Response:
def squeeze(self, trits, offset=0, length=None):
        # type: (MutableSequence[int], int, Optional[int]) -> None
        """
        Squeeze trits from the sponge into a buffer.

        :param trits:
            Buffer that will hold the squeezed trits.

            IMPORTANT:  If ``trits`` is too small, it will be extended!

        :param offset:
            Starting offset in ``trits``.

        :param length:
            Number of trits to squeeze from the sponge.

            If not specified, defaults to :py:data:`TRIT_HASH_LENGTH`
            (i.e., by default, we will try to squeeze exactly 1 hash).
        """
        # Pad input if necessary, so that it can be divided evenly into
        # hashes.
        pad = ((len(trits) % TRIT_HASH_LENGTH) or TRIT_HASH_LENGTH)
        trits += [0] * (TRIT_HASH_LENGTH - pad)

        if length is None:
            # By default, we will try to squeeze one hash.
            # Note that this is different than ``absorb``.
            length = len(trits) or TRIT_HASH_LENGTH

        if length < 1:
            raise with_context(
                exc=ValueError('Invalid length passed to ``squeeze``.'),

                context={
                    'trits': trits,
                    'offset': offset,
                    'length': length,
                },
            )

        while offset < length:
            unsigned_hash = self.k.digest()

            if PY2:
                unsigned_hash = map(ord, unsigned_hash)  # type: ignore

            signed_hash = [conv.convert_sign(b) for b in unsigned_hash]

            trits_from_hash = conv.convertToTrits(signed_hash)
            trits_from_hash[TRIT_HASH_LENGTH - 1] = 0

            stop = min(TRIT_HASH_LENGTH, length - offset)
            trits[offset:offset + stop] = trits_from_hash[0:stop]

            flipped_bytes = bytearray(
                conv.convert_sign(~b) for b in unsigned_hash
            )

            # Reset internal state before feeding back in.
            self.reset()
            self.k.update(flipped_bytes)

            offset += TRIT_HASH_LENGTH


Instruction:
Create a Python 3 function to
add a context value to an exception.

Response:
def with_context(exc, context):
    # type: (Exception, dict) -> Exception
    """
    Attaches a ``context`` value to an Exception.

    Before:

    .. code-block:: python

        exc = Exception('Frog blast the vent core!')
        exc.context = { ... }
        raise exc

    After:

    .. code-block:: python

        raise with_context(
            exc=Exception('Frog blast the vent core!'),
            context={ ... },
        )
    """
    if not hasattr(exc, 'context'):
        exc.context = {}

    exc.context.update(context)
    return exc


Instruction:
Can you generate the documentation for the following Python 3 function
def SecurityLevel():
    return (
            f.Type(int) |
            f.Min(1) |
            f.Max(3) |
            f.Optional(default=AddressGenerator.DEFAULT_SECURITY_LEVEL)
    )

Response: Generates a filter chain for validating a security level.


Instruction:
How would you implement a function in Python 3 that
returns a TryteString representation of the transaction.

Response:
def as_tryte_string(self):
        # type: () -> TryteString
        """
        Returns a TryteString representation of the transaction.
        """
        if not self.bundle_hash:
            raise with_context(
                exc=RuntimeError(
                    'Cannot get TryteString representation of {cls} instance '
                    'without a bundle hash; call ``bundle.finalize()`` first '
                    '(``exc.context`` has more info).'.format(
                        cls=type(self).__name__,
                    ),
                ),

                context={
                    'transaction': self,
                },
            )

        return super(ProposedTransaction, self).as_tryte_string()


Instruction:
Implement a Python 3 function for
incrementing the legacy tag of the current transaction.

Response:
def increment_legacy_tag(self):
        """
        Increments the transaction's legacy tag, used to fix insecure
        bundle hashes when finalizing a bundle.

        References:

        - https://github.com/iotaledger/iota.lib.py/issues/84
        """
        self._legacy_tag = (
            Tag.from_trits(add_trits(self.legacy_tag.as_trits(), [1]))
        )


Instruction:
Can you create a Python 3 function that
determines the most relevant tag for the bundle.

Response:
def tag(self):
        # type: () -> Tag
        """
        Determines the most relevant tag for the bundle.
        """
        for txn in reversed(self):  # type: ProposedTransaction
            if txn.tag:
                return txn.tag

        return Tag(b'')


Instruction:
How would you explain what the following Python 3 function does
def add_transaction(self, transaction):
        # type: (ProposedTransaction) -> None
        """
        Adds a transaction to the bundle.

        If the transaction message is too long, it will be split
        automatically into multiple transactions.
        """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if transaction.value < 0:
            raise ValueError('Use ``add_inputs`` to add inputs to the bundle.')

        self._transactions.append(ProposedTransaction(
            address=transaction.address,
            value=transaction.value,
            tag=transaction.tag,
            message=transaction.message[:Fragment.LEN],
            timestamp=transaction.timestamp,
        ))

        # If the message is too long to fit in a single transactions,
        # it must be split up into multiple transactions so that it will
        # fit.
        fragment = transaction.message[Fragment.LEN:]
        while fragment:
            self._transactions.append(ProposedTransaction(
                address=transaction.address,
                value=0,
                tag=transaction.tag,
                message=fragment[:Fragment.LEN],
                timestamp=transaction.timestamp,
            ))

            fragment = fragment[Fragment.LEN:]

Response: Adds a transaction to the bundle.


Instruction:
Make a summary of the following Python 3 code
def add_inputs(self, inputs):
        # type: (Iterable[Address]) -> None
        """
        Adds inputs to spend in the bundle.

        Note that each input may require multiple transactions, in order
        to hold the entire signature.

        :param inputs:
            Addresses to use as the inputs for this bundle.

            .. important::
                Must have ``balance`` and ``key_index`` attributes!
                Use :py:meth:`iota.api.get_inputs` to prepare inputs.
        """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        for addy in inputs:
            if addy.balance is None:
                raise with_context(
                    exc=ValueError(
                        'Address {address} has null ``balance`` '
                        '(``exc.context`` has more info).'.format(
                            address=addy,
                        ),
                    ),

                    context={
                        'address': addy,
                    },
                )

            if addy.key_index is None:
                raise with_context(
                    exc=ValueError(
                        'Address {address} has null ``key_index`` '
                        '(``exc.context`` has more info).'.format(
                            address=addy,
                        ),
                    ),

                    context={
                        'address': addy,
                    },
                )

            self._create_input_transactions(addy)

Response: Adds inputs to spend in the bundle.


Instruction:
Given the following Python 3 function, write the documentation
def finalize(self):
        # type: () -> None
        """
        Finalizes the bundle, preparing it to be attached to the Tangle.
        """
        if self.hash:
            raise RuntimeError('Bundle is already finalized.')

        if not self:
            raise ValueError('Bundle has no transactions.')

        # Quick validation.
        balance = self.balance

        if balance < 0:
            if self.change_address:
                self.add_transaction(ProposedTransaction(
                    address=self.change_address,
                    value=-balance,
                    tag=self.tag,
                ))
            else:
                raise ValueError(
                    'Bundle has unspent inputs (balance: {balance}); '
                    'use ``send_unspent_inputs_to`` to create '
                    'change transaction.'.format(
                        balance=balance,
                    ),
                )
        elif balance > 0:
            raise ValueError(
                'Inputs are insufficient to cover bundle spend '
                '(balance: {balance}).'.format(
                    balance=balance,
                ),
            )

        # Generate bundle hash.
        while True:
            sponge = Kerl()
            last_index = len(self) - 1

            for i, txn in enumerate(self):
                txn.current_index = i
                txn.last_index = last_index

                sponge.absorb(txn.get_signature_validation_trytes().as_trits())

            bundle_hash_trits = [0] * HASH_LENGTH
            sponge.squeeze(bundle_hash_trits)

            bundle_hash = BundleHash.from_trits(bundle_hash_trits)

            # Check that we generated a secure bundle hash.
            # https://github.com/iotaledger/iota.lib.py/issues/84
            if any(13 in part for part in normalize(bundle_hash)):
                # Increment the legacy tag and try again.
                tail_transaction = (
                    self.tail_transaction
                )  # type: ProposedTransaction
                tail_transaction.increment_legacy_tag()
            else:
                break

        # Copy bundle hash to individual transactions.
        for txn in self:
            txn.bundle_hash = bundle_hash

            # Initialize signature/message fragment.
            txn.signature_message_fragment = Fragment(txn.message or b'')

Response: Finalizes the bundle, preparing it to be attached to the Tangle.


Instruction:
Implement a Python 3 function for
signing the inputs in a finalized bundle.

Response:
def sign_inputs(self, key_generator):
        # type: (KeyGenerator) -> None
        """
        Sign inputs in a finalized bundle.
        """
        if not self.hash:
            raise RuntimeError('Cannot sign inputs until bundle is finalized.')

        # Use a counter for the loop so that we can skip ahead as we go.
        i = 0
        while i < len(self):
            txn = self[i]

            if txn.value < 0:
                # In order to sign the input, we need to know the index
                # of the private key used to generate it.
                if txn.address.key_index is None:
                    raise with_context(
                        exc=ValueError(
                            'Unable to sign input {input}; '
                            '``key_index`` is None '
                            '(``exc.context`` has more info).'.format(
                                input=txn.address,
                            ),
                        ),

                        context={
                            'transaction': txn,
                        },
                    )

                if txn.address.security_level is None:
                    raise with_context(
                        exc=ValueError(
                            'Unable to sign input {input}; '
                            '``security_level`` is None '
                            '(``exc.context`` has more info).'.format(
                                input=txn.address,
                            ),
                        ),

                        context={
                            'transaction': txn,
                        },
                    )

                self.sign_input_at(i, key_generator.get_key_for(txn.address))

                i += txn.address.security_level
            else:
                # No signature needed (nor even possible, in some
                # cases); skip this transaction.
                i += 1


Instruction:
Write a Python 3 script for
signing the input at the specified index.

Response:
def sign_input_at(self, start_index, private_key):
        # type: (int, PrivateKey) -> None
        """
        Signs the input at the specified index.

        :param start_index:
            The index of the first input transaction.

            If necessary, the resulting signature will be split across
            multiple transactions automatically (i.e., if an input has
            ``security_level=2``, you still only need to call
            :py:meth:`sign_input_at` once).

        :param private_key:
            The private key that will be used to generate the signature.

            .. important::
                Be sure that the private key was generated using the
                correct seed, or the resulting signature will be
                invalid!
        """
        if not self.hash:
            raise RuntimeError('Cannot sign inputs until bundle is finalized.')

        private_key.sign_input_transactions(self, start_index)


Instruction:
How would you code a function in Python 3 to
create transactions for the input address.

Response:
def _create_input_transactions(self, addy):
        # type: (Address) -> None
        """
        Creates transactions for the specified input address.
        """
        self._transactions.append(ProposedTransaction(
            address=addy,
            tag=self.tag,

            # Spend the entire address balance; if necessary, we will
            # add a change transaction to the bundle.
            value=-addy.balance,
        ))

        # Signatures require additional transactions to store, due to
        # transaction length limit.
        # Subtract 1 to account for the transaction we just added.
        for _ in range(addy.security_level - 1):
            self._transactions.append(ProposedTransaction(
                address=addy,
                tag=self.tag,

                # Note zero value; this is a meta transaction.
                value=0,
            ))


Instruction:
Can you generate the documentation for the following Python 3 function
def convert_value_to_standard_unit(value, symbol='i'):
    # type: (Text, Text) -> float
    """
    Converts between any two standard units of iota.

    :param value:
        Value (affixed) to convert. For example: '1.618 Mi'.

    :param symbol:
        Unit symbol of iota to convert to. For example: 'Gi'.

    :return:
        Float as units of given symbol to convert to.
    """
    try:
        # Get input value
        value_tuple = value.split()
        amount = float(value_tuple[0])
    except (ValueError, IndexError, AttributeError):
        raise with_context(
            ValueError('Value to convert is not valid.'),

            context={
                'value': value,
            },
        )

    try:
        # Set unit symbols and find factor/multiplier.
        unit_symbol_from = value_tuple[1]
        unit_factor_from = float(STANDARD_UNITS[unit_symbol_from])
        unit_factor_to = float(STANDARD_UNITS[symbol])
    except (KeyError, IndexError):
        # Invalid symbol or no factor
        raise with_context(
            ValueError('Invalid IOTA unit.'),

            context={
                'value': value,
                'symbol': symbol,
            },
        )

    return amount * (unit_factor_from / unit_factor_to)

Response: Converts a value to a standard unit of the given symbol.


Instruction:
Explain what the following Python 3 code does
def modular_squareroot_in_FQ2(value: FQ2) -> FQ2:
    candidate_squareroot = value ** ((FQ2_order + 8) // 16)
    check = candidate_squareroot ** 2 / value
    if check in eighth_roots_of_unity[::2]:
        x1 = candidate_squareroot / eighth_roots_of_unity[eighth_roots_of_unity.index(check) // 2]
        x2 = -x1
        x1_re, x1_im = x1.coeffs
        x2_re, x2_im = x2.coeffs
        return x1 if (x1_im > x2_im or (x1_im == x2_im and x1_re > x2_re)) else x2
    return None

Response: Return the modular squareroot in FQ2.


Instruction:
Make a summary of the following Python 3 code
def compress_G1(pt: G1Uncompressed) -> G1Compressed:
    if is_inf(pt):
        # Set c_flag = 1 and b_flag = 1. leave a_flag = x = 0
        return G1Compressed(POW_2_383 + POW_2_382)
    else:
        x, y = normalize(pt)
        # Record y's leftmost bit to the a_flag
        a_flag = (y.n * 2) // q
        # Set c_flag = 1 and b_flag = 0
        return G1Compressed(x.n + a_flag * POW_2_381 + POW_2_383)

Response: Compress a G1 compressed point.


Instruction:
Explain what the following Python 3 code does
def decompress_G1(z: G1Compressed) -> G1Uncompressed:
    # b_flag == 1 indicates the infinity point
    b_flag = (z % POW_2_383) // POW_2_382
    if b_flag == 1:
        return Z1
    x = z % POW_2_381

    # Try solving y coordinate from the equation Y^2 = X^3 + b
    # using quadratic residue
    y = pow((x**3 + b.n) % q, (q + 1) // 4, q)

    if pow(y, 2, q) != (x**3 + b.n) % q:
        raise ValueError(
            "The given point is not on G1: y**2 = x**3 + b"
        )
    # Choose the y whose leftmost bit is equal to the a_flag
    a_flag = (z % POW_2_382) // POW_2_381
    if (y * 2) // q != a_flag:
        y = q - y
    return (FQ(x), FQ(y), FQ(1))

Response: Decompress a G1 compressed point into a G1Uncompressed object.


Instruction:
Can you write a function in Python 3 where it
compresses a G2 point.

Response:
def compress_G2(pt: G2Uncompressed) -> G2Compressed:
    """
    The compressed point (z1, z2) has the bit order:
    z1: (c_flag1, b_flag1, a_flag1, x1)
    z2: (c_flag2, b_flag2, a_flag2, x2)
    where
    - c_flag1 is always set to 1
    - b_flag1 indicates infinity when set to 1
    - a_flag1 helps determine the y-coordinate when decompressing,
    - a_flag2, b_flag2, and c_flag2 are always set to 0
    """
    if not is_on_curve(pt, b2):
        raise ValueError(
            "The given point is not on the twisted curve over FQ**2"
        )
    if is_inf(pt):
        return G2Compressed((POW_2_383 + POW_2_382, 0))
    x, y = normalize(pt)
    x_re, x_im = x.coeffs
    y_re, y_im = y.coeffs
    # Record the leftmost bit of y_im to the a_flag1
    # If y_im happens to be zero, then use the bit of y_re
    a_flag1 = (y_im * 2) // q if y_im > 0 else (y_re * 2) // q

    # Imaginary part of x goes to z1, real part goes to z2
    # c_flag1 = 1, b_flag1 = 0
    z1 = x_im + a_flag1 * POW_2_381 + POW_2_383
    # a_flag2 = b_flag2 = c_flag2 = 0
    z2 = x_re
    return G2Compressed((z1, z2))


Instruction:
Can you write a function in Python 3 where it
decompresses a G2Compressed object.

Response:
def decompress_G2(p: G2Compressed) -> G2Uncompressed:
    """
    Recovers x and y coordinates from the compressed point (z1, z2).
    """
    z1, z2 = p

    # b_flag == 1 indicates the infinity point
    b_flag1 = (z1 % POW_2_383) // POW_2_382
    if b_flag1 == 1:
        return Z2

    x1 = z1 % POW_2_381
    x2 = z2
    # x1 is the imaginary part, x2 is the real part
    x = FQ2([x2, x1])
    y = modular_squareroot_in_FQ2(x**3 + b2)
    if y is None:
        raise ValueError("Failed to find a modular squareroot")

    # Choose the y whose leftmost bit of the imaginary part is equal to the a_flag1
    # If y_im happens to be zero, then use the bit of y_re
    a_flag1 = (z1 % POW_2_382) // POW_2_381
    y_re, y_im = y.coeffs
    if (y_im > 0 and (y_im * 2) // q != a_flag1) or (y_im == 0 and (y_re * 2) // q != a_flag1):
        y = FQ2((y * -1).coeffs)

    if not is_on_curve((x, y, FQ2([1, 0])), b2):
        raise ValueError(
            "The given point is not on the twisted curve over FQ**2"
        )
    return (x, y, FQ2([1, 0]))


Instruction:
Can you generate the documentation for the following Python 3 function
def prime_field_inv(a: int, n: int) -> int:
    if a == 0:
        return 0
    lm, hm = 1, 0
    low, high = a % n, n
    while low > 1:
        r = high // low
        nm, new = hm - lm * r, high - low * r
        lm, low, hm, high = nm, new, lm, low
    return lm % n

Response: Calculates the prime field inverses for a modular field.


Instruction:
Can you tell what is the following Python 3 function doing
def from_json_file(cls, filename):
        with open(filename, 'r') as fp:
            return cls(json.load(fp))

Response: Load a lexicon from a JSON file.


Instruction:
Make a summary of the following Python 3 code
def find_word_groups(self, text, category, proximity=2):
        f = re.IGNORECASE
        words = getattr(self, category)
        regex = re.compile(r'(\b' + r'\b|\b'.join(words) + r'\b)', flags=f)
        candidates = regex.finditer(text)

        starts, ends = [], []
        groups = []

        for item in candidates:
            starts.append(item.span()[0])
            ends.append(item.span()[1])
            groups.append(item.group().lower())

        new_starts = []  # As a check only.
        new_groups = []  # This is what I want.

        skip = False
        for i, g in enumerate(groups):
            if skip:
                skip = False
                continue
            if (i < len(groups)-1) and (starts[i+1]-ends[i] <= proximity):
                if g[-1] == '-':
                    sep = ''  # Don't insert spaces after hyphens.
                else:
                    sep = ' '
                new_groups.append(g + sep + groups[i+1])
                new_starts.append(starts[i])
                skip = True
            else:
                if g not in new_groups:
                    new_groups.append(g)
                    new_starts.append(starts[i])
                skip = False

        return new_groups

Response: Given a string and a category find and combine words into groups based on their proximity.


Instruction:
Write a Python 3 script for
giving a string and a dict of synonyms returns the preferred word. Case insensitive.

Response:
def find_synonym(self, word):
        """
        Given a string and a dict of synonyms, returns the 'preferred'
        word. Case insensitive.

        Args:
            word (str): A word.

        Returns:
            str: The preferred word, or the input word if not found.

        Example:
            >>> syn = {'snake': ['python', 'adder']}
            >>> find_synonym('adder', syn)
            'snake'
            >>> find_synonym('rattler', syn)
            'rattler'

        TODO:
            Make it handle case, returning the same case it received.
        """
        if word and self.synonyms:
            # Make the reverse look-up table.
            reverse_lookup = {}
            for k, v in self.synonyms.items():
                for i in v:
                    reverse_lookup[i.lower()] = k.lower()

            # Now check words against this table.
            if word.lower() in reverse_lookup:
                return reverse_lookup[word.lower()]

        return word


Instruction:
Create a Python 3 function to
parse a piece of text and replace any abbreviations with their full word equivalents.

Response:
def expand_abbreviations(self, text):
        """
        Parse a piece of text and replace any abbreviations with their full
        word equivalents. Uses the lexicon.abbreviations dictionary to find
        abbreviations.

        Args:
            text (str): The text to parse.

        Returns:
            str: The text with abbreviations replaced.
        """
        if not self.abbreviations:
            raise LexiconError("No abbreviations in lexicon.")

        def chunks(data, SIZE=25):
            """
            Regex only supports 100 groups for munging callbacks. So we have to
            chunk the abbreviation dicitonary.
            """
            it = iter(data)
            for i in range(0, len(data), SIZE):
                yield {k: data[k] for k in islice(it, SIZE)}

        def cb(g):
            """Regex callback"""
            return self.abbreviations.get(g.group(0)) or g.group(0)

        # Special cases.

        # TODO: We should handle these with a special set of
        # replacements that are made before the others.
        text = re.sub(r'w/', r'wi', text)

        # Main loop.
        for subdict in chunks(self.abbreviations):
            regex = r'(\b' + r'\b)|(\b'.join(subdict.keys()) + r'\b)'
            text = re.sub(regex, cb, text)

        return text


Instruction:
Can you generate the documentation for the following Python 3 function
def get_component(self, text, required=False, first_only=True):
        component = {}

        for i, (category, words) in enumerate(self.__dict__.items()):

            # There is probably a more elegant way to do this.
            if category in SPECIAL:
                # There are special entries in the lexicon.
                continue

            groups = self.find_word_groups(text, category)

            if groups and first_only:
                groups = groups[:1]
            elif groups:
                # groups = groups
                pass
            else:
                groups = [None]
                if required:
                    with warnings.catch_warnings():
                        warnings.simplefilter("always")
                        w = "No lithology in lexicon matching '{0}'"
                        warnings.warn(w.format(text))

            filtered = [self.find_synonym(i) for i in groups]
            if first_only:
                component[category] = filtered[0]
            else:
                component[category] = filtered

        return component

Response: Takes a piece of text representing a lithologic description for one - term component and turns it into a dictionary containing the attributes of the component.


Instruction:
Write a Python 3 function that can
split a description into parts each of which can be turned into a single component.

Response:
def split_description(self, text):
        """
        Split a description into parts, each of which can be turned into
        a single component.
        """
        # Protect some special sequences.
        t = re.sub(r'(\d) ?in\. ', r'\1 inch ', text)  # Protect.
        t = re.sub(r'(\d) ?ft\. ', r'\1 feet ', t)  # Protect.

        # Transform all part delimiters to first splitter.
        words = getattr(self, 'splitters')
        try:
            splitter = words[0].strip()
        except:
            splitter = 'with'
        t = re.sub(r'\,?\;?\.? ?((under)?(less than)? \d+%) (?=\w)', r' '+splitter+' \1 ', t)

        # Split.
        f = re.IGNORECASE
        pattern = re.compile(r'(?:' + r'|'.join(words) + r')', flags=f)
        parts = filter(None, pattern.split(t))

        return [i.strip() for i in parts]


Instruction:
Create a Python 3 function for
listing the categories in the lexicon except the optional categories.

Response:
def categories(self):
        """
        Lists the categories in the lexicon, except the
        optional categories.

        Returns:
            list: A list of strings of category names.
        """
        keys = [k for k in self.__dict__.keys() if k not in SPECIAL]
        return keys


Instruction:
Make a summary of the following Python 3 code
def _repr_html_row_(self, keys):
        tr, th, c = '', '', ''
        r = '{v}	'
        h = '{k}	'
        for k in keys:
            v = self.__dict__.get(k)

            if k == '_colour':
                k = 'colour'
                c = utils.text_colour_for_hex(v)
                style = 'color:{}; background-color:{}'.format(c, v)
            else:
                style = 'color:black; background-color:white'

            if k == 'component':
                try:
                    v = v._repr_html_()
                except AttributeError:
                    v = v.__repr__()

            tr += r.format(v=v, stl=style)
            th += h.format(k=k)

        return th, tr

Response: Jupyter Notebook magic repr function as a row – used by Legend. _repr_html_


Instruction:
Explain what the following Python 3 code does
def random(cls, component):
        colour = random.sample([i for i in range(256)], 3)
        return cls({'colour': colour, 'component': component, 'width': 1.0})

Response: Returns a minimal Decor with a random colour.


Instruction:
Can you write a function in Python 3 where it
makes a simple plot of the component summaries of the current object.

Response:
def plot(self, fmt=None, fig=None, ax=None):
        """
        Make a simple plot of the Decor.

        Args:
            fmt (str): A Python format string for the component summaries.
            fig (Pyplot figure): A figure, optional. Use either fig or ax, not
                both.
            ax (Pyplot axis): An axis, optional. Use either fig or ax, not
                both.

        Returns:
            fig or ax or None. If you pass in an ax, you get it back. If you pass
                in a fig, you get it. If you pass nothing, the function creates a
                plot object as a side-effect.
        """

        u = 4     # aspect ratio of decor plot
        v = 0.25  # ratio of decor tile width

        r = None

        if (fig is None) and (ax is None):
            fig = plt.figure(figsize=(u, 1))
        else:
            r = fig

        if ax is None:
            ax = fig.add_axes([0.1*v, 0.1, 0.8*v, 0.8])
        else:
            r = ax

        rect1 = patches.Rectangle((0, 0),
                                  u*v, u*v,
                                  color=self.colour,
                                  lw=1,
                                  hatch=self.hatch,
                                  ec='k')
        ax.add_patch(rect1)
        ax.text(1.0+0.1*v*u, u*v*0.5,
                self.component.summary(fmt=fmt),
                fontsize=max(u, 15),
                verticalalignment='center',
                horizontalalignment='left')
        ax.set_xlim([0, u*v])
        ax.set_ylim([0, u*v])
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        ax.invert_yaxis()

        return r


Instruction:
Can you tell what is the following Python 3 function doing
def builtin(cls, name):
        names = {
                 'nsdoe': LEGEND__NSDOE,
                 'canstrat': LEGEND__Canstrat,
                 'nagmdm__6_2': LEGEND__NAGMDM__6_2,
                 'nagmdm__6_1': LEGEND__NAGMDM__6_1,
                 'nagmdm__4_3': LEGEND__NAGMDM__4_3,
                 'sgmc': LEGEND__SGMC,
                 }
        return cls.from_csv(text=names[name.lower()])

Response: Generate a builtin legend.


Instruction:
How would you explain what the following Python 3 function does
def builtin_timescale(cls, name):
        names = {
                 'isc': TIMESCALE__ISC,
                 'usgs_isc': TIMESCALE__USGS_ISC,
                 'dnag': TIMESCALE__DNAG,
                 }
        return cls.from_csv(text=names[name.lower()])

Response: Generate a default timescale legend. No arguments.


Instruction:
Write a Python 3 function that can
generate a random legend for a given list of components.

Response:
def random(cls, components, width=False, colour=None):
        """
        Generate a random legend for a given list of components.

        Args:
            components (list or Striplog): A list of components. If you pass
                a Striplog, it will use the primary components. If you pass a
                component on its own, you will get a random Decor.
            width (bool): Also generate widths for the components, based on the
                order in which they are encountered.
            colour (str): If you want to give the Decors all the same colour,
                provide a hex string.
        Returns:
            Legend or Decor: A legend (or Decor) with random colours.
        TODO:
            It might be convenient to have a partial method to generate an
            'empty' legend. Might be an easy way for someone to start with a
            template, since it'll have the components in it already.
        """
        try:  # Treating as a Striplog.
            list_of_Decors = [Decor.random(c)
                              for c
                              in [i[0] for i in components.unique if i[0]]
                              ]
        except:
            try:
                list_of_Decors = [Decor.random(c) for c in components.copy()]
            except:
                # It's a single component.
                list_of_Decors = [Decor.random(components)]

        if colour is not None:
            for d in list_of_Decors:
                d.colour = colour

        if width:
            for i, d in enumerate(list_of_Decors):
                d.width = i + 1

        return cls(list_of_Decors)


Instruction:
Write a Python 3 function for
creating a new object from a list of components and a file.

Response:
def from_image(cls, filename, components,
                   ignore=None,
                   col_offset=0.1,
                   row_offset=2):
        """
        A slightly easier way to make legends from images.

        Args:
            filename (str)
            components (list)
            ignore (list): Colours to ignore, e.g. "#FFFFFF" to ignore white.
            col_offset (Number): If < 1, interpreted as proportion of way
                across the image. If > 1, interpreted as pixels from left.
            row_offset (int): Number of pixels to skip at the top of each
                interval.
        """
        if ignore is None:
            ignore = []

        rgb = utils.loglike_from_image(filename, offset=col_offset)
        loglike = np.array([utils.rgb_to_hex(t) for t in rgb])

        # Get the pixels and colour values at 'tops' (i.e. changes).
        _, hexes = utils.tops_from_loglike(loglike, offset=row_offset)

        # Reduce to unique colours.
        hexes_reduced = []
        for h in hexes:
            if h not in hexes_reduced:
                if h not in ignore:
                    hexes_reduced.append(h)

        list_of_Decors = []
        for i, c in enumerate(components):
            d = Decor({'colour': hexes_reduced[i], 'component': c})
            list_of_Decors.append(d)

        return cls(list_of_Decors)


Instruction:
Create a Python 3 function for
reading a CSV file and generate a new Legend object.

Response:
def from_csv(cls, filename=None, text=None):
        """
        Read CSV text and generate a Legend.

        Args:
            string (str): The CSV string.

        In the first row, list the properties. Precede the properties of the
        component with 'comp ' or 'component '. For example:

        colour,  width, comp lithology, comp colour
        #FFFFFF, 0, ,
        #F7E9A6, 3, Sandstone, Grey
        #FF99CC, 2, Anhydrite,
        ... etc

        Note:
            To edit a legend, the easiest thing to do is probably this:

            - `legend.to_csv()`
            - Edit the legend, call it `new_legend`.
            - `legend = Legend.from_csv(text=new_legend)`
        """
        if (filename is None) and (text is None):
            raise LegendError("You must provide a filename or CSV text.")

        if (filename is not None):
            with open(filename, 'r') as f:
                text = f.read()

        try:
            f = StringIO(text)  # Python 3
        except TypeError:
            f = StringIO(unicode(text))  # Python 2

        r = csv.DictReader(f, skipinitialspace=True)
        list_of_Decors, components = [], []
        kind = 'component'
        for row in r:
            d, component = {}, {}
            for (k, v) in row.items():
                if (k in [None, '']):
                    continue
                if (v in [None, '']):
                    if k.lower() not in ['color', 'colour']:
                        continue
                if k[:4].lower() == 'comp':
                    prop = ' '.join(k.split()[1:])
                    if v.lower() == 'true':
                        component[prop] = True
                    elif v.lower() == 'false':
                        component[prop] = False
                    else:
                        try:
                            component[prop] = float(v)
                        except ValueError:
                            component[prop] = v.lower()

                elif k[:5].lower() == 'curve':
                    prop = ' '.join(k.split()[1:])
                    component[prop] = v.lower()
                    kind = 'curve'
                else:
                    try:
                        d[k] = float(v)
                    except ValueError:
                        d[k] = v.lower()

            this_component = Component(component)
            d[kind] = this_component

            # Check for duplicates and warn.
            if this_component in components:
                with warnings.catch_warnings():
                    warnings.simplefilter("always")
                    w = "This legend contains duplicate components."
                    warnings.warn(w)
            components.append(this_component)

            # Append to the master list and continue.
            list_of_Decors.append(Decor(d))

        return cls(list_of_Decors)


Instruction:
Can you generate the documentation for the following Python 3 function
def to_csv(self):
        # We can't delegate this to Decor because we need to know the superset
        # of all Decor properties. There may be lots of blanks.
        header = []
        component_header = []
        for row in self:
            for j in row.__dict__.keys():
                if j == '_colour':
                    j = 'colour'
                header.append(j)
            for k in row.component.__dict__.keys():
                component_header.append(k)
        header = set(header)
        component_header = set(component_header)
        header.remove('component')
        header_row = ''
        if 'colour' in header:
            header_row += 'colour,'
            header.remove('colour')
            has_colour = True
        for item in header:
            header_row += item + ','
        for item in component_header:
            header_row += 'component ' + item + ','

        # Now we have a header row! Phew.
        # Next we'll go back over the legend and collect everything.
        result = header_row.strip(',') + '\n'
        for row in self:
            if has_colour:
                result += row.__dict__.get('_colour', '') + ','
            for item in header:
                result += str(row.__dict__.get(item, '')) + ','
            for item in component_header:
                result += str(row.component.__dict__.get(item, '')) + ','
            result += '\n'

        return result

Response: Renders a legend as a CSV string.


Instruction:
Can you generate the documentation for the following Python 3 function
def max_width(self):
        try:
            maximum = max([row.width for row in self.__list if row.width is not None])
            return maximum
        except:
            return 0

Response: Returns the maximum width of all the Decors in the Legend.


Instruction:
Can you generate a brief explanation for the following Python 3 code
def get_decor(self, c, match_only=None):
        if isinstance(c, Component):
            if c:
                if match_only:
                    # Filter the component only those attributes
                    c = Component({k: getattr(c, k, None) for k in match_only})
                for decor in self.__list:
                    try:
                        if c == decor.component:
                            return decor
                    except AttributeError:
                        continue
        else:
            for decor in self.__list:
                try:
                    if getattr(c, 'mnemonic').lower() == decor.curve.mnemonic:
                        return decor
                except AttributeError:
                    continue
        return Decor({'colour': '#eeeeee', 'component': Component()})

Response: Get the decor for a component.


Instruction:
Can you create a Python 3 function that
gets the attribute of a component.

Response:
def getattr(self, c, attr, default=None, match_only=None):
        """
        Get the attribute of a component.

        Args:
           c (component): The component to look up.
           attr (str): The attribute to get.
           default (str): What to return in the event of no match.
           match_only (list of str): The component attributes to include in the
               comparison. Default: All of them.

        Returns:
           obj. The specified attribute of the matching Decor in the Legend.
        """
        matching_decor = self.get_decor(c, match_only=match_only)

        try:
            return getattr(matching_decor, attr)
        except AttributeError:
            return default