import contextlib

from cupy.cuda import compiler  # NOQA
from cupy.cuda import device  # NOQA
from cupy.cuda import function  # NOQA
from cupy.cuda import memory  # NOQA
from cupy.cuda import nvtx  # NOQA
from cupy.cuda import pinned_memory  # NOQA
from cupy.cuda import profiler  # NOQA
from cupy.cuda import stream  # NOQA


# import class and function
from cupy.cuda.compiler import compile_with_cache  # NOQA
from cupy.cuda.device import Device  # NOQA
from cupy.cuda.device import get_cublas_handle  # NOQA
from cupy.cuda.device import get_device_id  # NOQA
from cupy.cuda.function import Function  # NOQA
from cupy.cuda.function import Module  # NOQA
from cupy.cuda.memory import alloc  # NOQA
from cupy.cuda.memory import Memory  # NOQA
from cupy.cuda.memory import MemoryPointer  # NOQA
from cupy.cuda.memory import MemoryPool  # NOQA
from cupy.cuda.memory import set_allocator  # NOQA
from cupy.cuda.pinned_memory import alloc_pinned_memory  # NOQA
from cupy.cuda.pinned_memory import PinnedMemory  # NOQA
from cupy.cuda.pinned_memory import PinnedMemoryPointer  # NOQA
from cupy.cuda.pinned_memory import PinnedMemoryPool  # NOQA
from cupy.cuda.pinned_memory import set_pinned_memory_allocator  # NOQA
from cupy.cuda.stream import Event  # NOQA
from cupy.cuda.stream import get_elapsed_time  # NOQA
from cupy.cuda.stream import Stream  # NOQA


@contextlib.contextmanager
def profile():
    """Enable CUDA profiling during with statement.

    This function enables profiling on entering a with statement, and disables
    profiling on leaving the statement.

    >>> with cupy.cuda.profile():
    ...    # do something you want to measure
    ...    pass

    """
    profiler.start()
    try:
        yield
    finally:
        profiler.stop()


@contextlib.contextmanager
def timerange(message, id_color=-1):
    """A context manager to describe the enclosed block
    as a nested NVTX time range.

    Args:
        message (str): Name of a range.
        id_color (int): ID of color for a range.

    """
    nvtx.RangePush(message, id_color)
    try:
        yield
    finally:
        nvtx.RangePop()


@contextlib.contextmanager
def timerangeC(message, color=0):
    """A context manager to describe the enclosed block
    as a nested NVTX time range.

    Args:
        message (str): Name of a range.
        color (uint32): ARGB Color for a range.

    """
    nvtx.RangePushC(message, color)
    try:
        yield
    finally:
        nvtx.RangePop()

@@ -1863,36 +1863,32 @@
 e enclosed block
-%0A   
  as a nested NVT
@@ -1876,37 +1876,32 @@
 ock as a nested 
-NVTX 
 time range.%0A%0A   
@@ -1886,33 +1886,32 @@
 ested time range
-.
 %0A%0A    Args:%0A    
@@ -1988,32 +1988,122 @@
 r for a range.%0A%0A
+    .. seealso:: :func:%60cupy.cuda.nvtx.RangePush%60%0A        :func:%60cupy.cuda.nvtx.RangePop%60%0A
     %22%22%22%0A    nvtx
@@ -2310,20 +2310,16 @@
 ed block
-%0A   
  as a ne
@@ -2327,13 +2327,8 @@
 ted 
-NVTX 
 time
@@ -2329,25 +2329,24 @@
 d time range
-.
 %0A%0A    Args:%0A
@@ -2430,24 +2430,115 @@
 r a range.%0A%0A
+    .. seealso:: :func:%60cupy.cuda.nvtx.RangePushC%60%0A        :func:%60cupy.cuda.nvtx.RangePop%60%0A
     %22%22%22%0A    

update docstring to fix flake8 error and add seealso to cupy.cuda.nvtx