files: """
  ctypes wrappers for functions from the C API
  """
  import ctypes
  
  from .utils import load_libgmt
  from . import constants
  
  
  def create_session():
      """
      Create the ``GMTAPI_CTRL`` struct required by the GMT C API functions.
  
      It is a C void pointer containing the current session information and
      cannot be accessed directly.
  
      Remember to terminate the current session using
      :func:`gmt.clib.destroy_session` before creating a new one.
  
      Returns
      -------
      api_pointer : C void pointer (returned by ctypes as an integer)
          Used by GMT C API functions.
  
      """
      libgmt = load_libgmt()
      c_create_session = libgmt.GMT_Create_Session
      c_create_session.argtypes = [ctypes.c_char_p, ctypes.c_uint, ctypes.c_uint,
                                   ctypes.c_void_p]
      c_create_session.restype = ctypes.c_void_p
      # None is passed in place of the print function pointer. It becomes the
      # NULL pointer when passed to C, prompting the C API to use the default
      # print function.
      session = c_create_session(constants.GMT_SESSION_NAME,
                                 constants.GMT_PAD_DEFAULT,
                                 constants.GMT_SESSION_EXTERNAL,
                                 None)
      assert session is not None, \
          "Failed creating GMT API pointer using create_session."
      return session
  
  
  def destroy_session(session):
      """
      Terminate and free the memory of a registered ``GMTAPI_CTRL`` session.
  
      The session is created and consumed by the C API modules and needs to be
      freed before creating a new. Otherwise, some of the configuration files
      might be left behind and can influence subsequent API calls.
  
      Parameters
      ----------
      session : C void pointer (returned by ctypes as an integer)
          The active session object produced by :func:`gmt.clib.create_session`.
  
      """
      libgmt = load_libgmt()
      c_destroy_session = libgmt.GMT_Destroy_Session
      c_destroy_session.argtypes = [ctypes.c_void_p]
      c_destroy_session.restype = ctypes.c_int
      status = c_destroy_session(session)
      assert status is not None, 'Failed returning None.'
      assert status == 0, 'Failed with status code {}.'.format(status)
  
  
  def call_module(module, args):
      """
      Call a GMT module with the given arguments.
  
      Makes a call to ``GMT_Call_Module`` from the C API using mode
      ``GMT_MODULE_CMD`` (arguments passed as a single string).
  
      Most interactions with the C API are done through this function.
  
      Creates a new C API session (:func:`gmt.clib.create_session`) to pass to
      ``GMT_Call_Module`` and destroys it (:func:`gmt.clib.destroy_session`)
      after it is used. This is what the command-line interface of GMT does.
  
      Parameters
      ----------
      module : str
          Module name (``'pscoast'``, ``'psbasemap'``, etc).
      args : str
          String with the command line arguments that will be passed to the
          module (for example, ``'-R0/5/0/10 -JM'``).
  
      """
      mode = constants.GMT_MODULE_CMD
      libgmt = load_libgmt()
      c_call_module = libgmt.GMT_Call_Module
      c_call_module.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int,
                                ctypes.c_void_p]
      c_call_module.restype = ctypes.c_int
      session = create_session()
      status = c_call_module(session, module.encode(), mode, args.encode())
      destroy_session(session)
      assert status is not None, 'Failed returning None.'
      assert status == 0, 'Failed with status code {}.'.format(status)
  
files: gmt/clib/functions.py
files: """
  ctypes wrappers for functions from the C API
  """
  import ctypes
  
  from .utils import load_libgmt
  from . import constants
  
  
  def create_session():
      """
      Create the ``GMTAPI_CTRL`` struct required by the GMT C API functions.
  
      It is a C void pointer containing the current session information and
      cannot be accessed directly.
  
      Remember to terminate the current session using
      :func:`gmt.clib.destroy_session` before creating a new one.
  
      Returns
      -------
      api_pointer : C void pointer (returned by ctypes as an integer)
          Used by GMT C API functions.
  
      """
      libgmt = load_libgmt()
      c_create_session = libgmt.GMT_Create_Session
      c_create_session.argtypes = [ctypes.c_char_p, ctypes.c_uint, ctypes.c_uint,
                                   ctypes.c_void_p]
      c_create_session.restype = ctypes.c_void_p
      # None is passed in place of the print function pointer. It becomes the
      # NULL pointer when passed to C, prompting the C API to use the default
      # print function.
      session = c_create_session(constants.GMT_SESSION_NAME,
                                 constants.GMT_PAD_DEFAULT,
                                 constants.GMT_SESSION_EXTERNAL,
                                 None)
      assert session is not None, \
          "Failed creating GMT API pointer using create_session."
      return session
  
  
  def destroy_session(session):
      """
      Terminate and free the memory of a registered ``GMTAPI_CTRL`` session.
  
      The session is created and consumed by the C API modules and needs to be
      freed before creating a new. Otherwise, some of the configuration files
      might be left behind and can influence subsequent API calls.
  
      Parameters
      ----------
      session : C void pointer (returned by ctypes as an integer)
          The active session object produced by :func:`gmt.clib.create_session`.
  
      """
      libgmt = load_libgmt()
      c_destroy_session = libgmt.GMT_Destroy_Session
      c_destroy_session.argtypes = [ctypes.c_void_p]
      c_destroy_session.restype = ctypes.c_int
      status = c_destroy_session(session)
      assert status is not None, 'Failed returning None.'
      assert status == 0, 'Failed with status code {}.'.format(status)
  
  
  def call_module(session, module, args):
      """
      Call a GMT module with the given arguments.
  
      Makes a call to ``GMT_Call_Module`` from the C API using mode
      "GMT_MODULE_CMD" (arguments passed as a single string).
  
      Most interactions with the C API are done through this function.
  
      Parameters
      ----------
      session : ctypes.c_void_p
          A void pointer to a GMTAPI_CTRL structure created by
          :func:`gmt.clib.create_session`.
      module : str
          Module name (``'pscoast'``, ``'psbasemap'``, etc).
      args : str
          String with the command line arguments that will be passed to the
          module (for example, ``'-R0/5/0/10 -JM'``).
  
      """
      mode = constants.GMT_MODULE_CMD
      libgmt = load_libgmt()
      c_call_module = libgmt.GMT_Call_Module
      c_call_module.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int,
                                ctypes.c_void_p]
      c_call_module.restype = ctypes.c_int
      status = c_call_module(session, module.encode(), mode, args.encode())
      assert status is not None, 'Failed returning None.'
      assert status == 0, 'Failed with status code {}.'.format(status)
  
files: gmt/clib/functions.py
files: """
  Session management modules: begin, end, figure, clean
  """
  from . import clib
  
  
  def begin(prefix='gmtsession', fmt='pdf'):
      """
      Initiate a new GMT session using modern mode.
  
      Used in combination with :func:`gmt.end`.
  
      Parameters
      ----------
      prefix : str
          The prefix to use for unnamed figures.
      fmt : str
          Sets the default plot format for the output figures.
          Choose one of these valid extensions:
  
          * bmp:       MicroSoft BitMap.
          * eps:       Encapsulated PostScript.
          * jpg:       Joint Photographic Experts Group format.
          * pdf:       Portable Document Format [Default].
          * png:       Portable Network Graphics.
          * ppm:       Portable Pixel Map.
          * ps:        PostScript.
          * tif:       Tagged Image Format File.
      """
      clib.call_module('begin', '{} {}'.format(prefix, fmt))
  
  
  def end():
      """
      Terminate GMT modern mode session and optionally  produce the figure files.
  
      Called after :func:`gmt.begin` and all commands that you want included in a
      session. Will finalize any PostScript plots that were made in the
      background, convert them to the desired format (specified in
      ``gmt.begin``), and bring the figures to the working directory.
  
      """
      clib.call_module('end', '')
  
  
  # Not working yet (perhaps bug in GMT).
  def figure(prefix, formats='pdf', convertoptions='A,P'):
      """
      Start a new figure under a GMT modern mode session.
  
      Must be in a modern mode session (between calls to :func:`gmt.begin` and
      :func:`gmt.end`.
  
      Parameters
      ----------
      prefix : str
          The prefix to use for the next figure name.
      formats : str
          One or more comma-separated formats for the output figures.
          Choose from these valid extensions:
  
          * bmp:       MicroSoft BitMap.
          * eps:       Encapsulated PostScript.
          * jpg:       Joint Photographic Experts Group format.
          * pdf:       Portable Document Format [Default].
          * png:       Portable Network Graphics.
          * ppm:       Portable Pixel Map.
          * ps:        PostScript.
          * tif:       Tagged Image Format File.
  
      convertoptions : str
          One or more comma-separated options that will be passed to
          :func:`gmt.psconvert` when preparing the figures.
          The subset of valid options are:
          ``'A[<args>],C<args>,D<dir>,E<dpi>,P,Q<args>,S'``.
  
      """
      args = '{} {} {}'.format(prefix, formats, convertoptions)
      clib.call_module('figure', args)
  
files: gmt/session_management.py
files: """
  Session management modules: begin, end, figure, clean
  """
  from . import clib
  
  
  def begin(prefix='gmtsession', fmt='pdf'):
      """
      Initiate a new GMT session using modern mode.
  
      Used in combination with :func:`gmt.end`.
  
      Parameters
      ----------
      prefix : str
          The prefix to use for unnamed figures.
      fmt : str
          Sets the default plot format for the output figures.
          Choose one of these valid extensions:
  
          * bmp:       MicroSoft BitMap.
          * eps:       Encapsulated PostScript.
          * jpg:       Joint Photographic Experts Group format.
          * pdf:       Portable Document Format [Default].
          * png:       Portable Network Graphics.
          * ppm:       Portable Pixel Map.
          * ps:        PostScript.
          * tif:       Tagged Image Format File.
      """
      session = clib.create_session()
      clib.call_module(session, 'begin', '{} {}'.format(prefix, fmt))
  
  
  def end():
      """
      Terminate GMT modern mode session and optionally  produce the figure files.
  
      Called after :func:`gmt.begin` and all commands that you want included in a
      session. Will finalize any PostScript plots that were made in the
      background, convert them to the desired format (specified in
      ``gmt.begin``), and bring the figures to the working directory.
  
      """
      session = clib.create_session()
      clib.call_module(session, 'end', '')
  
  
  # Not working yet (perhaps bug in GMT).
  def figure(prefix, formats='pdf', convertoptions='A,P'):
      """
      Start a new figure under a GMT modern mode session.
  
      Must be in a modern mode session (between calls to :func:`gmt.begin` and
      :func:`gmt.end`.
  
      Parameters
      ----------
      prefix : str
          The prefix to use for the next figure name.
      formats : str
          One or more comma-separated formats for the output figures.
          Choose from these valid extensions:
  
          * bmp:       MicroSoft BitMap.
          * eps:       Encapsulated PostScript.
          * jpg:       Joint Photographic Experts Group format.
          * pdf:       Portable Document Format [Default].
          * png:       Portable Network Graphics.
          * ppm:       Portable Pixel Map.
          * ps:        PostScript.
          * tif:       Tagged Image Format File.
  
      convertoptions : str
          One or more comma-separated options that will be passed to
          :func:`gmt.psconvert` when preparing the figures.
          The subset of valid options are:
          ``'A[<args>],C<args>,D<dir>,E<dpi>,P,Q<args>,S'``.
  
      """
      session = clib.create_session()
      args = '{} {} {}'.format(prefix, formats, convertoptions)
      clib.call_module(session, 'figure', args)
  
files: gmt/session_management.py
files: """
  Test the wrappers for the C API.
  """
  import os
  
  from ..clib import create_session, destroy_session, call_module, load_libgmt
  
  
  def test_load_libgmt():
      "Test that loading libgmt works and doesn't crash."
      libgmt = load_libgmt()
      assert hasattr(libgmt, 'GMT_Create_Session')
  
  
  def test_clib_session_management():
      "Test that create and destroy session are called without errors"
      session1 = create_session()
      assert session1 is not None
      session2 = create_session()
      assert session2 is not None
      assert session2 != session1
      destroy_session(session1)
      destroy_session(session2)
  
  
  def test_call_module():
      "Run a psbasemap call to see if the module works"
      module = 'psbasemap'
      args = '-R10/70/-3/8 -JX4i/3i -Ba -P ->tmp.ps'
      call_module(module, args)
      assert os.path.exists('tmp.ps')
      os.remove('tmp.ps')
      # Not the most ideal test. Just check if no segfaults or exceptions occur.
  
files: gmt/tests/test_clib.py
files: """
  Test the wrappers for the C API.
  """
  import os
  
  from ..clib import create_session, destroy_session, call_module, load_libgmt
  
  
  def test_load_libgmt():
      "Test that loading libgmt works and doesn't crash."
      libgmt = load_libgmt()
      assert hasattr(libgmt, 'GMT_Create_Session')
  
  
  def test_clib_session_management():
      "Test that create and destroy session are called without errors"
      session1 = create_session()
      assert session1 is not None
      session2 = create_session()
      assert session2 is not None
      assert session2 != session1
      destroy_session(session1)
      destroy_session(session2)
  
  
  def test_call_module():
      "Run a psbasemap call to see if the module works"
      module = 'psbasemap'
      args = '-R10/70/-3/8 -JX4i/3i -Ba -P ->tmp.ps'
      session = create_session()
      call_module(session, module, args)
      destroy_session(session)
      assert os.path.exists('tmp.ps')
      os.remove('tmp.ps')
      # Not the most ideal test. Just check if no segfaults or exceptions occur.
  
files: gmt/tests/test_clib.py
files: """
  Test the session management modules.
  """
  import os
  
  from .. import begin, end, figure
  from ..clib import call_module
  from .utils import figure_comparison_test
  
  
  TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
  
  
  @figure_comparison_test
  def test_session(prefix, fmt):
      "Run a command inside a begin-end modern mode block."
      begin(prefix=prefix, fmt=fmt)
      call_module('psbasemap', '-R10/70/-3/8 -JX4i/3i -Ba -P')
      end()
  
  
  @figure_comparison_test
  def test_session_figure(prefix, fmt):
      "Run a figure command inside a begin-end modern mode block."
      begin()
      figure(prefix=prefix, formats=fmt)
      call_module('psbasemap', '-R10/70/-3/8 -JX4i/3i -Ba -P')
      # Plot some points with red circles
      data_file = os.path.join(TEST_DATA_DIR, 'points.txt')
      call_module('psxy', '-<{} -Sc -Gred'.format(data_file))
      end()
  
files: gmt/tests/test_session_management.py
files: """
  Test the session management modules.
  """
  import os
  
  from .. import begin, end, figure
  from ..clib import call_module, create_session
  from .utils import figure_comparison_test
  
  
  TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
  
  
  @figure_comparison_test
  def test_session(prefix, fmt):
      "Run a command inside a begin-end modern mode block."
      begin(prefix=prefix, fmt=fmt)
      session = create_session()
      call_module(session, 'psbasemap', '-R10/70/-3/8 -JX4i/3i -Ba -P')
      end()
  
  
  @figure_comparison_test
  def test_session_figure(prefix, fmt):
      "Run a figure command inside a begin-end modern mode block."
      begin()
      figure(prefix=prefix, formats=fmt)
      session = create_session()
      call_module(session, 'psbasemap', '-R10/70/-3/8 -JX4i/3i -Ba -P')
      # Plot some points with red circles
      data_file = os.path.join(TEST_DATA_DIR, 'points.txt')
      call_module(session, 'psxy', '-<{} -Sc -Gred'.format(data_file))
      end()
  
files: gmt/tests/test_session_management.py