diff --git a/.gitignore b/.gitignore
index a007feab071f496a016f150e1acd8fae57669cce..e5cc0d85013408f24b1e13a352e68896d480664a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
 build/*
+*.pyc
+__pycache__/*
+.pytest_cache/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..492658052283c6cb92c487c36eda253eedce3ebb
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.10)
+
+find_package(SWIG REQUIRED)
+include(${SWIG_USE_FILE})
+
+add_subdirectory(python)
\ No newline at end of file
diff --git a/csm.i b/csm.i
new file mode 100644
index 0000000000000000000000000000000000000000..227014a0a20fe01dbf02cd7d7d9512e010e41c4f
--- /dev/null
+++ b/csm.i
@@ -0,0 +1,25 @@
+%module(package="csmapi") csm
+%{
+    #include "csm.h"
+%}
+
+%ignore CSM_UNKNOWN;
+%ignore CSM_SENSOR_TYPE_UNKNOWN;     
+%ignore CSM_SENSOR_TYPE_EO;            
+%ignore CSM_SENSOR_TYPE_IR;            
+%ignore CSM_SENSOR_TYPE_MWIR;          
+%ignore CSM_SENSOR_TYPE_LWIR;          
+%ignore CSM_SENSOR_TYPE_SAR;           
+%ignore CSM_SENSOR_TYPE_EOIRSC;        
+%ignore CSM_SENSOR_MODE_UNKNOWN;       
+%ignore CSM_SENSOR_MODE_FRAME;        
+%ignore CSM_SENSOR_MODE_PULSE;         
+%ignore CSM_SENSOR_MODE_PB;            
+%ignore CSM_SENSOR_MODE_WB;            
+%ignore CSM_SENSOR_MODE_SPOT;          
+%ignore CSM_SENSOR_MODE_STRIP;         
+%ignore CSM_SENSOR_MODE_SCAN;          
+%ignore CSM_SENSOR_MODE_VIDEO;         
+%ignore CSM_SENSOR_MODE_BODY_POINTING; 
+
+%include "csm.h"
diff --git a/csmapi.i b/csmapi.i
new file mode 100644
index 0000000000000000000000000000000000000000..1cec5ae97687a418fda404134a81e1a3e5d8cf6e
--- /dev/null
+++ b/csmapi.i
@@ -0,0 +1,9 @@
+%module csmapi
+%include "csm.i"
+%include "version.i"
+%include "ellipsoid.i"
+%include "warning.i"
+%include "isd.i"
+%include "rastergm.i"
+%include "plugin.i"
+%include "model.i"
\ No newline at end of file
diff --git a/ellipsoid.i b/ellipsoid.i
new file mode 100644
index 0000000000000000000000000000000000000000..b428582ae54f4ba1394405396a8b160965b3b8d2
--- /dev/null
+++ b/ellipsoid.i
@@ -0,0 +1,9 @@
+%module(package="csmapi") ellipsoid
+%{
+    #include "Ellipsoid.h"
+%}
+
+%ignore CSM_WGS84_SEMI_MAJOR_AXIS;
+%ignore CSM_WGS84_SEMI_MINOR_AXIS;
+
+%include "Ellipsoid.h"
diff --git a/isd.i b/isd.i
new file mode 100644
index 0000000000000000000000000000000000000000..f2e88869406042f612af630e1acff5d54071cdcf
--- /dev/null
+++ b/isd.i
@@ -0,0 +1,38 @@
+%module(package="csmapi") isd
+%{
+    #include "Isd.h"
+%}
+
+%ignore IMAGE_ID_PARAM;
+%ignore IMAGE_ID_PARAM;      
+%ignore IMAGE_INDEX_PARAM;
+%ignore LOGICAL_INDEX_PARAM;
+%ignore MODEL_NAME_PARAM;
+
+%include <std_string.i>
+
+%include "Isd.h"
+%pythoncode %{
+  import json
+  import numpy as np
+  @classmethod
+  def loads(cls, stream):
+      isd = cls()
+      if not isinstance(stream, dict):
+          stream = json.loads(stream)
+      for k, v in stream.items():
+          if isinstance(v, np.ndarray):
+              v = v.tolist()
+          if isinstance(v, list):
+              for i in v:
+                  isd.addParam(k, str(i))
+          isd.addParam(k, str(v))
+      return isd
+
+  @classmethod
+  def load(cls, fp):
+      return cls.loads(fp.read())
+
+  Isd.load = load
+  Isd.loads = loads
+%}
\ No newline at end of file
diff --git a/model.i b/model.i
new file mode 100644
index 0000000000000000000000000000000000000000..cdd9305071cc244ffd864b3ec2b497b0fabc0292
--- /dev/null
+++ b/model.i
@@ -0,0 +1,7 @@
+%module(package="csmapi") model
+%{
+    #include "Model.h"
+%}
+
+%include Model.h
+
diff --git a/plugin.i b/plugin.i
new file mode 100644
index 0000000000000000000000000000000000000000..590fe179b05e0cff560ad7395a249fa6dc56b4ce
--- /dev/null
+++ b/plugin.i
@@ -0,0 +1,29 @@
+%module(package="csmapi") plugin
+%{
+    #include "Plugin.h"
+%}
+
+%include <std_string.i>
+%include <std_list.i>
+%include typemaps.i
+%include Plugin.h
+
+
+
+
+%template(PluginList) std::list<const csm::Plugin*>;
+
+%{
+    namespace swig {
+    template <> struct traits<csm::Plugin>
+    {
+        typedef pointer_category category;
+        static const char* type_name()
+        {
+            return "Plugin";
+        }
+    };
+    }
+%}
+
+
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4addffdca46767a7ab5ef66abe84f5fa8d488697
--- /dev/null
+++ b/python/CMakeLists.txt
@@ -0,0 +1,41 @@
+# Include python
+find_package(PythonLibs REQUIRED)
+include_directories(${PYTHON_INCLUDE_PATH})
+
+
+set(CMAKE_SWIG_FLAGS "")
+set_source_files_properties(../csmapi.i 
+                            PROPERTIES CPLUSPLUS ON)
+
+find_path(CSM_INCLUDE_DIR NAMES csm.h PATH_SUFFIXES csm)
+find_library(CSM_LIBRARY NAMES csmapi)
+
+include_directories(${CSM_INCLUDE_DIR})
+
+# Add swig module
+swig_add_library(csmapi
+                 LANGUAGE python 
+                 SOURCES ../csmapi.i)
+
+
+swig_link_libraries(csmapi ${CSM_LIBRARY} ${PYTHON_LIBRARIES})
+
+# Files to install with Python
+set(PYTHON_INSTALL_FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/csmapi.py
+    ${CMAKE_CURRENT_BINARY_DIR}/_csmapi.so)
+
+# Configure setup.py and copy to output directory
+set(SETUP_PY_IN ${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in)
+set(SETUP_PY_OUT ${CMAKE_CURRENT_BINARY_DIR}/setup.py)
+configure_file(${SETUP_PY_IN} ${SETUP_PY_OUT})
+
+# Declare install target for python
+#install(TARGETS swig_example
+#        COMMAND "${PYTHON_EXECUTABLE} setup.py"
+#        COMPONENT swig-python)
+
+# Install target to call setup.py
+add_custom_target(install-python
+        DEPENDS _csmapi
+COMMAND python ${SETUP_PY_OUT} install)
diff --git a/python/setup.py.in b/python/setup.py.in
new file mode 100644
index 0000000000000000000000000000000000000000..1494b0d525a07891e713c8e265f7e343dd27aeee
--- /dev/null
+++ b/python/setup.py.in
@@ -0,0 +1,14 @@
+import setuptools.command.install
+import shutil
+from distutils.sysconfig import get_python_lib
+
+if __name__ == '__main__':
+    setuptools.setup(
+        name='csmapi',
+        version='0.1.0',
+        py_modules=['csmapi'],
+        package_data={'csmapi':['_csmapi.so']},
+        license='UnLicense',
+        author='jlaura',
+        author_email='jlaura@usgs.gov'
+)
diff --git a/rastergm.i b/rastergm.i
new file mode 100644
index 0000000000000000000000000000000000000000..64b658f189b0f1afcd828e901b99a5a6e816cc99
--- /dev/null
+++ b/rastergm.i
@@ -0,0 +1,8 @@
+%module(package="csmapi") rastergm
+%{
+    #include "RasterGM.h"
+%}
+
+%ignore CSM_RASTER_FAMILY;
+
+%include RasterGM.h
\ No newline at end of file
diff --git a/tests/test_functional.py b/tests/test_functional.py
new file mode 100644
index 0000000000000000000000000000000000000000..0746b1f646cb93438af391b9daf7cbe3b8dda0f0
--- /dev/null
+++ b/tests/test_functional.py
@@ -0,0 +1,48 @@
+import ctypes
+from distutils import dir_util
+import json
+import os
+
+import pytest
+
+import csmapi
+
+# Load a plugin with CSM compliant sensors
+lib = ctypes.CDLL('/data/big/github/CSM-CameraModel/build/libusgscsm.so')
+
+@pytest.fixture
+def datadir(tmpdir, request):
+    '''
+    Fixture responsible for searching a folder with the same name of test
+    module and, if available, moving all contents to a temporary directory so
+    tests can use them freely.
+    '''
+    filename = request.module.__file__
+    test_dir, _ = os.path.splitext(filename)
+
+    if os.path.isdir(test_dir):
+        dir_util.copy_tree(test_dir, str(tmpdir))
+    return tmpdir
+
+@pytest.fixture
+def isd(datadir):
+    with open(datadir.join('simpleFramerISD.json')) as f:
+        i = csmapi.Isd.load(f)
+    return i
+    
+
+@pytest.fixture
+def plugin():
+    plugin = csmapi.Plugin.findPlugin('UsgsAstroFramePluginCSM')
+    return plugin 
+
+def test_isd_to_model_to_ground(isd, plugin):
+    model_name = "USGS_ASTRO_FRAME_SENSOR_MODEL"
+    assert plugin.canModelBeConstructedFromISD(isd, model_name)
+    assert plugin.canISDBeConvertedToModelState(isd, model_name)
+    
+    model = plugin.constructModelFromISD(isd, model_name)
+    assert model.getVersion().version() == '0.1.0'
+    print(dir(model))
+    assert False
+    
\ No newline at end of file
diff --git a/tests/test_functional/simpleFramerISD.json b/tests/test_functional/simpleFramerISD.json
new file mode 100644
index 0000000000000000000000000000000000000000..8e4f7ebf41509e3650ba9fee69708d594f0d7ede
--- /dev/null
+++ b/tests/test_functional/simpleFramerISD.json
@@ -0,0 +1,96 @@
+{
+    "boresight": [
+        0.0,
+        0.0,
+        1.0
+    ],
+    "ccd_center": [
+        7.5,
+        7.5
+    ],
+    "ephemeris_time": 100.0,
+    "focal_length": 500,
+    "focal_length_epsilon": 1.0,
+    "ifov": 6.0,
+    "model_name": "UsgsAstroFramePluginCSM",
+    "spacecraft_name": "TEST_CRAFT",
+    "instrument_id": "TEST_SENSOR",
+    "target_name": "TEST_BALL",
+    "pixel_pitch": 0.1,
+    "itrans_line": [
+        0.0,
+        0.0,
+        10
+    ],
+    "itrans_sample": [
+        0.0,
+        10,
+        0.0
+    ],
+    "transx": [
+        0.0,
+        0.1,
+        0.0
+    ],
+    "transy": [
+        0.0,
+        0.0,
+        0.1
+    ],
+    "min_elevation": -1,
+    "max_elevation": 1,
+    "nlines": 16,
+    "nsamples": 16,
+    "original_half_lines": 8.0,
+    "original_half_samples": 8.0,
+    "omega": 0,
+    "phi": 0,
+    "kappa": 0,
+    "semi_major_axis": 10,
+    "semi_minor_axis": 10,
+    "transx": [
+        0.0,
+        0.1,
+        0.0
+    ],
+    "transy": [
+        0.0,
+        0.0,
+        0.1
+    ],
+    "x_sensor_origin": 1000,
+    "y_sensor_origin": 0,
+    "z_sensor_origin": 0,
+    "x_sensor_velocity": 1,
+    "y_sensor_velocity": 0,
+    "z_sensor_velocity": 0,
+    "x_sun_position": 100,
+    "y_sun_position": 100,
+    "z_sun_position": 0,
+    "odt_x": [
+        0.0,
+        1.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0
+    ],
+    "odt_y": [
+        0.0,
+        0.0,
+        1.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0,
+        0.0
+    ],
+    "starting_detector_line": 0.0,
+    "starting_detector_sample": 0.0
+}
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..e3424316b511e414bca63a2dc7f876bcfb2edd37
--- /dev/null
+++ b/tests/test_plugin.py
@@ -0,0 +1,34 @@
+import pytest
+
+import csmapi
+import ctypes
+
+# Load a plugin with CSM compliant sensors
+lib = ctypes.CDLL('/data/big/github/CSM-CameraModel/build/libusgscsm.so')
+
+@pytest.fixture
+def plugin():
+    return csmapi.Plugin
+
+@pytest.fixture
+def model(plugin):
+    pl = plugin.findPlugin('UsgsAstroFramePluginCSM')
+    return pl  
+
+def test_plugin_size(plugin):
+    plugin_list = plugin.getList()
+    assert len(plugin_list) == 2
+
+@pytest.mark.parametrize("plugin, index, expected_name",
+                         [(plugin(), 0, 'UsgsAstroFramePluginCSM'),
+                          (plugin(), 1, 'USGS_ASTRO_LINE_SCANNER_PLUGIN')])
+def test_plugin_name(plugin, index, expected_name):
+    pl = plugin.getList()[index]
+    plugin_name = pl.getPluginName()
+    assert plugin_name == expected_name
+
+def test_model_getNumModels(model):
+    assert model.getNumModels() == 1
+
+def test_model_getModelName(model):
+    assert model.getModelName(0) == 'USGS_ASTRO_FRAME_SENSOR_MODEL'
\ No newline at end of file
diff --git a/usgs.i b/usgs.i
new file mode 100644
index 0000000000000000000000000000000000000000..4520657b544dcdad16def98abfcf87f07fdb91b6
--- /dev/null
+++ b/usgs.i
@@ -0,0 +1,6 @@
+%module(package="csmapi") usgs
+%{
+    #include "UsgsAstroLsPlugin.h"
+%}
+
+%import "UsgsAstroLsPlugin.h"
\ No newline at end of file
diff --git a/version.i b/version.i
new file mode 100644
index 0000000000000000000000000000000000000000..e775da1e5755d60d2c8833b2b17fbce2c6d31a48
--- /dev/null
+++ b/version.i
@@ -0,0 +1,7 @@
+%module(package="csmapi") version
+%{
+    #include "Version.h"
+%}
+
+%include <std_string.i>
+%include "Version.h"
diff --git a/warning.i b/warning.i
new file mode 100644
index 0000000000000000000000000000000000000000..04e85d4cc0b520b15ff4cf90fff77b58bccc6fd0
--- /dev/null
+++ b/warning.i
@@ -0,0 +1,6 @@
+%module(package="csmapi") warning
+%{
+    #include "Warning.h"
+%}
+
+%include Warning.h
\ No newline at end of file