diff --git a/build/Jamfile b/build/Jamfile
index 34f99dde73..4e16a2f146 100644
--- a/build/Jamfile
+++ b/build/Jamfile
@@ -48,6 +48,7 @@ lib boost_python
     tuple.cpp
     str.cpp
     slice.cpp
+    set.cpp
 
     converter/from_python.cpp
     converter/registry.cpp
diff --git a/include/boost/python/set.hpp b/include/boost/python/set.hpp
new file mode 100644
index 0000000000..350683e3ac
--- /dev/null
+++ b/include/boost/python/set.hpp
@@ -0,0 +1,100 @@
+// Copyright Fady Essam 2019. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#ifndef SET_BOOST_PYTHON_HH
+#define SET_BOOST_PYTHON_HH
+
+#include <boost/python/ssize_t.hpp>
+#include <boost/python.hpp>
+
+
+namespace boost {
+  namespace python {
+
+	namespace detail
+	{
+	  struct BOOST_PYTHON_DECL set_base : object
+	  {
+		void add(object_cref); // add object to set
+
+		object pop(); // remove and return item at top
+
+		void discard(object_cref x); // discard value from set
+
+		long __len__(); // length of set
+
+		void clear(); // empties set
+
+	  protected:
+		set_base();
+		explicit set_base(object_cref sequence); // new set initialized from sequence's items
+
+		BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(set_base, object)
+	  private:
+		static detail::new_non_null_reference call(object const&);
+	  };
+
+
+	}
+
+
+
+
+
+
+	class set : public detail::set_base
+	{
+	  typedef detail::set_base base;
+	public:
+	  set() {}
+
+	  template <class T>
+	  explicit set(T const& sequence)
+		: base(object(sequence))
+	  {
+	  }
+
+	  template <class T>
+	  void add(T const& x)
+	  {
+		base::add(object(x));
+	  }
+
+	  object pop() { return base::pop(); }
+
+	  template <class T>
+	  void discard(T const& value)
+	  {
+		base::discard(object(value));
+	  }
+
+	  void clear() { base::clear(); }
+
+	  long __len__() { return base::__len__(); }
+
+
+
+	public:
+	  BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(set, base)
+	};
+
+
+	namespace converter
+	{
+	  template <>
+	  struct object_manager_traits<set>
+		: pytype_object_manager_traits<&PySet_Type, set>
+	  {
+	  };
+	}
+
+
+  }
+
+}
+
+
+
+
+
+#endif // !SET_BOOST_PYTHON_HH
diff --git a/src/fabscript b/src/fabscript
index 0ebeac6098..df9f6935ad 100644
--- a/src/fabscript
+++ b/src/fabscript
@@ -17,6 +17,7 @@ bpl = library('boost_python' + root.py_suffix,
               ['list.cpp',
                'long.cpp',
                'dict.cpp',
+               'set.cpp',
                'tuple.cpp',
                'str.cpp',
                'slice.cpp',
diff --git a/src/set.cpp b/src/set.cpp
new file mode 100644
index 0000000000..4abc463a71
--- /dev/null
+++ b/src/set.cpp
@@ -0,0 +1,83 @@
+// Copyright Fady Essam 2019. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/python/set.hpp>
+
+
+namespace boost {
+  namespace python {
+	namespace detail {
+
+
+	  detail::new_non_null_reference set_base::call(object_cref arg_)
+	  {
+		return (detail::new_non_null_reference)
+		  (expect_non_null)(
+			PySet_New(arg_.ptr())
+			);
+	  }
+
+	  set_base::set_base()
+		: object(detail::new_reference(PySet_New(NULL)))
+	  {}
+
+	  set_base::set_base(object_cref sequence)
+		: object(set_base::call(sequence))
+	  {}
+
+	  void set_base::add(object_cref x)
+	  {
+		if (PyAnySet_CheckExact(this->ptr()))
+		{
+		  if (PySet_Add(this->ptr(), x.ptr()) == -1)
+			throw_error_already_set();
+		}
+		else
+		{
+		  this->attr("add")(x);
+		}
+	  }
+
+
+	  void set_base::discard(object_cref x)
+	  {
+		if (PyAnySet_CheckExact(this->ptr()))
+		{
+		  if (PySet_Discard(this->ptr(), x.ptr()) == -1)
+			throw_error_already_set();
+		}
+		else
+		{
+		  this->attr("discrad")(x);
+		}
+	  }
+
+	  object set_base::pop()
+	  {
+		return this->attr("pop")();
+	  }
+
+	  void set_base::clear()
+	  {
+		this->attr("clear")();
+	  }
+
+	  long set_base::__len__()
+	  {
+		return extract<long>(object(PySet_Size(this->ptr())))();
+	  }
+
+
+	  static struct register_set_pytype_ptr
+	  {
+		register_set_pytype_ptr()
+		{
+		  const_cast<converter::registration &>(
+			converter::registry::lookup(boost::python::type_id<boost::python::set>())
+			).m_class_object = &PySet_Type;
+		}
+	  }register_set_pytype_ptr_;
+
+	}
+  }
+}
diff --git a/test/Jamfile b/test/Jamfile
index 9a5c756956..6d01673beb 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -135,6 +135,7 @@ bpl-test crossmod_exception
 [ bpl-test list ]
 [ bpl-test long ]
 [ bpl-test dict ]
+[ bpl-test set ]
 [ bpl-test tuple ]
 [ bpl-test str ]
 [ bpl-test slice ]
diff --git a/test/fabscript b/test/fabscript
index 1989cc0d13..39586cb52e 100644
--- a/test/fabscript
+++ b/test/fabscript
@@ -81,6 +81,7 @@ for t in [('injected',),
           ('list',),
           ('long',),
           ('dict',),
+          ('set',),
           ('tuple',),
           ('str',),
           ('slice',),
diff --git a/test/set.cpp b/test/set.cpp
new file mode 100644
index 0000000000..e38c8ed78d
--- /dev/null
+++ b/test/set.cpp
@@ -0,0 +1,79 @@
+// Copyright Fady Essam 2019. Distributed under the Boost
+// Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <boost/python/module.hpp>
+#define BOOST_ENABLE_ASSERT_HANDLER
+#include <boost/assert.hpp>
+
+#include <boost/python/def.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/set.hpp>
+#include <exception>
+#include <string>
+#include <iostream>
+
+using namespace boost::python;
+
+object new_set()
+{
+  return set();
+}
+
+object data_set()
+{
+  set tmp1;
+  tmp1.add("value1");
+
+  tmp1.add(2);
+  return tmp1;
+}
+
+object set_from_sequence(object sequence)
+{
+  return set(sequence);
+}
+
+
+void work_with_set(set data1)
+{
+  if (!data1.contains("k1")) {
+	std::cout << "data1 doesn't have k1" << std::endl;
+  }
+  data1.add("k1");
+
+  if (data1.contains("k1")) {
+	std::cout << "data1 now has k1" << std::endl;
+  }
+
+  data1.discard("k1");
+  if (!data1.contains("k1")) {
+	std::cout << "data1 doesn't have k1 again" << std::endl;
+  }
+
+}
+
+void test_templates(object print)
+{
+  std::string key = "key";
+
+  set tmp;
+  tmp.add("a test string");
+  print(tmp);
+  tmp.add(13);
+  print(tmp.contains(1.5));
+  print(tmp.contains(13));
+  print(tmp);
+
+  BOOST_ASSERT(tmp.__len__() == 2);
+}
+
+BOOST_PYTHON_MODULE(set_ext)
+{
+  def("new_set", new_set);
+  def("data_set", data_set);
+  def("set_from_sequence", set_from_sequence);
+  def("work_with_set", work_with_set);
+  def("test_templates", test_templates);
+}
+
+#include "module_tail.cpp"
diff --git a/test/set.py b/test/set.py
new file mode 100644
index 0000000000..3cd72ca050
--- /dev/null
+++ b/test/set.py
@@ -0,0 +1,34 @@
+# Copyright Fady Essam 2019. Distributed under the Boost
+# Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+from __future__ import print_function
+"""
+>>> import set_ext
+>>> set_ext.new_set()
+set()
+>>> set_ext.data_set()
+{2, 'value1'}
+>>> set_ext.set_from_sequence([1,2,3,3])
+{1, 2, 3}
+>>> s = set_ext.new_set()
+>>> set_ext.test_templates(print)
+{'a test string'}
+False
+True
+{'a test string', 13}
+"""
+
+def run(args = None):
+    import sys
+    import doctest
+
+    if args is not None:
+        sys.argv = args
+    return doctest.testmod(sys.modules.get(__name__))
+    
+if __name__ == '__main__':
+    print("running...")
+    import sys
+    status = run()[0]
+    if (status == 0): print("Done.")
+    sys.exit(status)