Repository: mandiant/capa
File: capa/features/extractors/base_extractor.py (Python)

Code before:
                            print('0x%x: %s', address, feature)

        args:
          f [FunctionHandle]: an opaque value previously fetched from `.get_functions()`.
          bb [BBHandle]: an opaque value previously fetched from `.get_basic_blocks()`.
          insn [InsnHandle]: an opaque value previously fetched from `.get_instructions()`.

        yields:
          Tuple[Feature, Address]: feature and its location
        """
        raise NotImplementedError()


@dataclass
class ProcessHandle:
    """
    reference to a process extracted by the sandbox.

    Attributes:
        ppid: parent process id
        pid: process id
        inner: sandbox-specific data
    """

    ppid: int
    pid: int
    inner: Any


@dataclass
class ThreadHandle:
    """
    reference to a thread extracted by the sandbox.

    Attributes:
        tid: thread id
        inner: sandbox-specific data
    """

    tid: int
    inner: Any


class DynamicExtractor(FeatureExtractor):
    """
    DynamicExtractor defines the interface for fetching features from a sandbox' analysis of a sample.

    Features are grouped mainly into threads that alongside their meta-features are also grouped into 
    processes (that also have their own features). Other scopes (such as function and file) may also apply 
    for a specific sandbox.


Review comment (refactor):
hm, now that i think about this: this is the abstract interface for dynamic handles, which means that all implementors *must* be able to provide this data. if we're not sure that its available, then we should rely on implementors to subclass and/or use the `inner` property.

with that in mind, i think we should at least remove ppid. im not sure about using pid/tid. for the time being, lets keep this, with the understanding that as we add support for other sandboxes, we might have to change this interface.
```suggestion
    pid: int
```

Code after:
                            print('0x%x: %s', address, feature)

        args:
          f [FunctionHandle]: an opaque value previously fetched from `.get_functions()`.
          bb [BBHandle]: an opaque value previously fetched from `.get_basic_blocks()`.
          insn [InsnHandle]: an opaque value previously fetched from `.get_instructions()`.

        yields:
          Tuple[Feature, Address]: feature and its location
        """
        raise NotImplementedError()


@dataclass
class ProcessHandle:
    """
    reference to a process extracted by the sandbox.

    Attributes:
        pid: process id
        inner: sandbox-specific data
    """

    pid: int
    inner: Any


@dataclass
class ThreadHandle:
    """
    reference to a thread extracted by the sandbox.

    Attributes:
        tid: thread id
        inner: sandbox-specific data
    """

    tid: int
    inner: Any


class DynamicExtractor(FeatureExtractor):
    """
    DynamicExtractor defines the interface for fetching features from a sandbox' analysis of a sample.

    Features are grouped mainly into threads that alongside their meta-features are also grouped into 
    processes (that also have their own features). Other scopes (such as function and file) may also apply 
    for a specific sandbox.

    This class is not instantiated directly; it is the base class for other implementations.
    """