public static PyObject wrap(Object object) {
    // Simple case
    if (object == null) return Py.None;

    if (object instanceof PyObject) return (PyObject) object;

    final Class<?> objectClass = object.getClass();

    if (object.getClass().isArray()) {
      final PyList pyList = new PyList();
      for (int i = Array.getLength(object); --i >= 0; ) {
        pyList.add(wrap(Array.get(object, i)));
      }
      return pyList;
    }

    // Wrapper case
    // Wrapper case -- go up in the hierarchy
    for (Map.Entry<Class, Constructor> entry : WRAPPERS.entrySet()) {
      if (entry.getKey().isAssignableFrom(objectClass)) {
        try {
          return new PythonObject(entry.getValue().newInstance(object));
        } catch (Exception e) {
          throw new UnsupportedOperationException(
              "Could not wrap object of class " + objectClass, e);
        }
      }
    }

    // Simple types
    if (object instanceof String) {
      return new PyString((String) object);
    }

    if (object instanceof Boolean) {
      return new PyBoolean(((Boolean) object).booleanValue());
    }

    if (object instanceof Long) {
      return new PyLong((long) object);
    }

    if (object instanceof Number) {
      return new PyFloat(((Number) object).doubleValue());
    }

    // Exposed objects
    final Exposed exposed = objectClass.getAnnotation(Exposed.class);
    if (exposed != null) {
      return new PythonObject(object);
    }

    // Map entry as tuple
    if (object instanceof Map.Entry) {
      Map.Entry entry = (Map.Entry) object;
      return new PyTuple(wrap(entry.getKey()), wrap(entry.getValue()));
    }

    // Entry set
    if (object instanceof Set) {
      Set set = (Set) object;

      final AbstractSet wrappedSet =
          new AbstractSet() {
            @Override
            public Iterator iterator() {
              return new Iterator() {
                Iterator iterator = set.iterator();

                @Override
                public boolean hasNext() {
                  return iterator.hasNext();
                }

                @Override
                public Object next() {
                  return wrap(iterator.next());
                }
              };
            }

            @Override
            public int size() {
              return 0;
            }
          };
      return new PySet(wrappedSet, null);
    }

    if (object instanceof Iterator) {
      return PythonUtils.wrapIterator((Iterator) object);
    }

    throw new IllegalArgumentException(
        format("Cannot wrap class %s into python object", objectClass));
  }