]> code.bitgloo.com Git - clyne/entityx.git/commitdiff
Move Python support to https://github.com/alecthomas/entityx_python
authorAlec Thomas <alec@swapoff.org>
Sat, 21 Dec 2013 01:57:02 +0000 (20:57 -0500)
committerAlec Thomas <alec@swapoff.org>
Sat, 21 Dec 2013 01:57:02 +0000 (20:57 -0500)
15 files changed:
CMakeLists.txt
entityx/python/PythonSystem.cc [deleted file]
entityx/python/PythonSystem.h [deleted file]
entityx/python/PythonSystem_test.cc [deleted file]
entityx/python/README.md [deleted file]
entityx/python/entityx/__init__.py [deleted file]
entityx/python/entityx/tests/__init__.py [deleted file]
entityx/python/entityx/tests/assign_test.py [deleted file]
entityx/python/entityx/tests/constructor_test.py [deleted file]
entityx/python/entityx/tests/create_entities_from_python_test.py [deleted file]
entityx/python/entityx/tests/deep_subclass_test.py [deleted file]
entityx/python/entityx/tests/event_emit_test.py [deleted file]
entityx/python/entityx/tests/event_test.py [deleted file]
entityx/python/entityx/tests/update_test.py [deleted file]
entityx/python/setup.py [deleted file]

index f49c75f3811635ddd1c98b6185250baf7c268ffa..af6d17ca6c7febee6a2023acd72a88c4e61ac6dd 100644 (file)
@@ -13,7 +13,6 @@ set(ENTITYX_RUN_BENCHMARKS false CACHE BOOL "Run benchmarks (in conjunction with
 set(ENTITYX_MAX_COMPONENTS 64 CACHE STRING "Set the maximum number of components.")
 set(ENTITYX_USE_CPP11_STDLIB true CACHE BOOL "For Clang, specify whether to use libc++ (-stdlib=libc++).")
 set(ENTITYX_BUILD_SHARED false CACHE BOOL "Build shared libraries?")
-set(ENTITYX_BUILD_PYTHON false CACHE BOOL "Build entityx::python?")
 
 include(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake)
 include(CheckCXXSourceCompiles)
@@ -91,13 +90,6 @@ require(HAS_CXX11_LONG_LONG "C++11 lambdas")
 message("-- Checking misc features")
 require(HAVE_STDINT_H "stdint.h")
 
-if (ENTITYX_BUILD_PYTHON)
-    message("-- Building with Python support (-DENTITYX_BUILD_PYTHON=0 to disable)")
-    find_package(Boost 1.48.0 COMPONENTS python)
-else (ENTITYX_BUILD_PYTHON)
-    message("-- Python support disabled")
-endif (ENTITYX_BUILD_PYTHON)
-
 set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
 set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
 set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
@@ -119,35 +111,6 @@ if (ENTITYX_BUILD_SHARED)
     list(APPEND install_libs entityx_shared)
 endif (ENTITYX_BUILD_SHARED)
 
-if (ENTITYX_BUILD_PYTHON AND Boost_PYTHON_LIBRARY)
-    message("-- Found boost::python, building entityx/python")
-    find_package(PythonLibs REQUIRED)
-    include_directories(${PYTHON_INCLUDE_DIRS})
-    set(ENTITYX_HAVE_BOOST_PYTHON 1)
-    set(python_sources entityx/python/PythonSystem.cc)
-    add_library(entityx_python STATIC ${python_sources})
-    list(APPEND install_libs entityx_python)
-    install(
-        FILES ${CMAKE_CURRENT_SOURCE_DIR}/entityx/python/entityx/__init__.py
-        DESTINATION share/entityx/python/
-        RENAME entityx.py
-    )
-    message("-- Installing entityx Python package to ${CMAKE_INSTALL_PREFIX}/share/entityx/python")
-    set(ENTITYX_INSTALLED_PYTHON_PACKAGE_DIR ${CMAKE_INSTALL_PREFIX}/share/entityx/python/)
-    if (ENTITYX_BUILD_SHARED)
-        add_library(entityx_python_shared SHARED ${python_sources})
-        target_link_libraries(
-            entityx_python_shared
-            entityx_shared
-            ${Boost_PYTHON_LIBRARY}
-            ${PYTHON_LIBRARIES}
-        )
-        set_target_properties(entityx_python_shared PROPERTIES OUTPUT_NAME entityx_python)
-        list(APPEND install_libs entityx_python_shared)
-    endif (ENTITYX_BUILD_SHARED)
-    set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
-endif (ENTITYX_BUILD_PYTHON AND Boost_PYTHON_LIBRARY)
-
 if (ENTITYX_BUILD_TESTING)
     #find_package(Boost 1.48.0 REQUIRED COMPONENTS timer system)
     add_subdirectory(gtest-1.6.0)
@@ -158,10 +121,6 @@ if (ENTITYX_BUILD_TESTING)
     create_test(system_test entityx/System_test.cc)
     create_test(tags_component_test entityx/tags/TagsComponent_test.cc)
     create_test(dependencies_test entityx/deps/Dependencies_test.cc)
-    if (Boost_PYTHON_LIBRARY)
-        add_definitions(-DENTITYX_PYTHON_TEST_DATA=\"${CMAKE_CURRENT_SOURCE_DIR}/entityx/python\")
-        create_test(python_test entityx/python/PythonSystem_test.cc entityx_python ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARIES})
-    endif (Boost_PYTHON_LIBRARY)
     if (ENTITYX_RUN_BENCHMARKS)
         message("-- Running benchmarks")
         add_definitions(-DGTEST_USE_OWN_TR1_TUPLE=1 -DBOOST_NO_CXX11_NUMERIC_LIMITS=1)
diff --git a/entityx/python/PythonSystem.cc b/entityx/python/PythonSystem.cc
deleted file mode 100644 (file)
index 373948d..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Copyright (C) 2013 Alec Thomas <alec@swapoff.org>
- * All rights reserved.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution.
- *
- * Author: Alec Thomas <alec@swapoff.org>
- */
-
-// http://docs.python.org/2/extending/extending.html
-#include <boost/noncopyable.hpp>
-#include <Python.h>
-#include <cassert>
-#include <string>
-#include <iostream>
-#include <sstream>
-#include "entityx/python/PythonSystem.h"
-
-namespace py = boost::python;
-
-namespace entityx {
-namespace python {
-
-
-static const py::object None;
-
-
-class PythonEntityXLogger {
-public:
-  PythonEntityXLogger() {}
-  explicit PythonEntityXLogger(PythonSystem::LoggerFunction logger) : logger_(logger) {}
-  ~PythonEntityXLogger() { flush(true); }
-
-  void write(const std::string &text) {
-    line_ += text;
-    flush();
-  }
-
-private:
-  void flush(bool force = false) {
-    size_t offset;
-    while ((offset = line_.find('\n')) != std::string::npos) {
-      std::string text = line_.substr(0, offset);
-      logger_(text);
-      line_ = line_.substr(offset + 1);
-    }
-    if (force && line_.size()) {
-      logger_(line_);
-      line_ = "";
-    }
-  }
-
-  PythonSystem::LoggerFunction logger_;
-  std::string line_;
-};
-
-
-/**
- * Base class for Python entities.
- */
-struct PythonEntity {
-  explicit PythonEntity(ptr<EntityManager> entity_manager, Entity::Id id) : _entity(Entity(entity_manager, id)) {}  // NOLINT
-  virtual ~PythonEntity() {}
-
-  void destroy() {
-    _entity.destroy();
-  }
-
-  operator Entity () const { return _entity; }
-
-  virtual void update(float dt, int frame) {}
-
-  Entity::Id _entity_id() const {
-    return _entity.id();
-  }
-
-  Entity _entity;
-};
-
-static std::string PythonEntity_repr(const PythonEntity &entity) {
-  std::stringstream repr;
-  repr << "<Entity " << entity._entity.id().index() << "." << entity._entity.id().version() << ">";
-  return repr.str();
-}
-
-
-static std::string Entity_Id_repr(Entity::Id id) {
-  std::stringstream repr;
-  repr << "<Entity::Id " << id.index() << "." << id.version() << ">";
-  return repr.str();
-}
-
-
-// static std::string entity_repr(Entity entity) {
-//   std::stringstream repr;
-//   repr << "<Entity::Id " << entity.id().index() << "." << entity.id().version() << ">";
-//   return repr.str();
-// }
-
-// static bool entity_eq(Entity left, Entity right) {
-//   return left.id() == right.id();
-// }
-
-
-// A to-Python converter from Entity to PythonEntity.
-struct EntityToPythonEntity {
-  static PyObject *convert(Entity entity) {
-    auto python = entity.component<PythonComponent>();
-    assert(python && "Entity does not have a PythonComponent");
-    return py::incref(python->object.ptr());
-  }
-};
-
-
-Entity::Id EntityManager_configure(ptr<EntityManager> entity_manager, py::object self) {
-  Entity entity = entity_manager->create();
-  entity.assign<PythonComponent>(self);
-  return entity.id();
-}
-
-BOOST_PYTHON_MODULE(_entityx) {
-  py::to_python_converter<Entity, EntityToPythonEntity>();
-
-  py::class_<PythonEntityXLogger>("Logger", py::no_init)
-    .def("write", &PythonEntityXLogger::write);
-
-  py::class_<BaseEvent, ptr<BaseEvent>, boost::noncopyable>("BaseEvent", py::no_init);
-
-  py::class_<PythonEntity>("Entity", py::init<ptr<EntityManager>, Entity::Id>())
-    .def_readonly("_entity_id", &PythonEntity::_entity_id)
-    .def("update", &PythonEntity::update)
-    .def("destroy", &PythonEntity::destroy)
-    .def("__repr__", &PythonEntity_repr);
-
-  py::class_<Entity::Id>("EntityId", py::no_init)
-    .def_readonly("id", &Entity::Id::id)
-    .def_readonly("index", &Entity::Id::index)
-    .def_readonly("version", &Entity::Id::version)
-    .def("__repr__", &Entity_Id_repr);
-
-  py::class_<PythonComponent, ptr<PythonComponent>>("PythonComponent", py::init<py::object>())
-    .def("assign_to", &assign_to<PythonComponent>)
-    .def("get_component", &get_component<PythonComponent>)
-    .staticmethod("get_component");
-
-  py::class_<EntityManager, ptr<EntityManager>, boost::noncopyable>("EntityManager", py::no_init)
-    .def("configure", &EntityManager_configure);
-
-  void (EventManager::*emit)(const BaseEvent &) = &EventManager::emit;
-
-  py::class_<EventManager, ptr<EventManager>, boost::noncopyable>("EventManager", py::no_init)
-    .def("emit", emit);
-
-  py::implicitly_convertible<PythonEntity, Entity>();
-}
-
-
-static void log_to_stderr(const std::string &text) {
-  std::cerr << "python stderr: " << text << std::endl;
-}
-
-static void log_to_stdout(const std::string &text) {
-  std::cout << "python stdout: " << text << std::endl;
-}
-
-// PythonSystem below here
-
-bool PythonSystem::initialized_ = false;
-
-PythonSystem::PythonSystem(ptr<EntityManager> entity_manager)
-    : entity_manager_(entity_manager), stdout_(log_to_stdout), stderr_(log_to_stderr) {
-  if (!initialized_) {
-    initialize_python_module();
-  }
-  Py_Initialize();
-  if (!initialized_) {
-    init_entityx();
-    initialized_ = true;
-  }
-}
-
-PythonSystem::~PythonSystem() {
-  try {
-    py::object entityx = py::import("_entityx");
-    entityx.attr("_entity_manager").del();
-    entityx.attr("_event_manager").del();
-    py::object sys = py::import("sys");
-    sys.attr("stdout").del();
-    sys.attr("stderr").del();
-    py::object gc = py::import("gc");
-    gc.attr("collect")();
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    throw;
-  }
-  // FIXME: It would be good to do this, but it is not supported by boost::python:
-  // http://www.boost.org/doc/libs/1_53_0/libs/python/todo.html#pyfinalize-safety
-  // Py_Finalize();
-}
-
-void PythonSystem::add_installed_library_path() {
-  add_path(ENTITYX_INSTALLED_PYTHON_PACKAGE_DIR);
-}
-
-void PythonSystem::add_path(const std::string &path) {
-  python_paths_.push_back(path);
-}
-
-void PythonSystem::initialize_python_module() {
-  assert(PyImport_AppendInittab("_entityx", init_entityx) != -1 && "Failed to initialize _entityx Python module");
-}
-
-void PythonSystem::configure(ptr<EventManager> event_manager) {
-  event_manager->subscribe<EntityDestroyedEvent>(*this);
-  event_manager->subscribe<ComponentAddedEvent<PythonComponent>>(*this);
-
-  try {
-    py::object main_module = py::import("__main__");
-    py::object main_namespace = main_module.attr("__dict__");
-
-    // Initialize logging.
-    py::object sys = py::import("sys");
-    sys.attr("stdout") = PythonEntityXLogger(stdout_);
-    sys.attr("stderr") = PythonEntityXLogger(stderr_);
-
-    // Add paths to interpreter sys.path
-    for (auto path : python_paths_) {
-      py::str dir = path.c_str();
-      sys.attr("path").attr("insert")(0, dir);
-    }
-
-    py::object entityx = py::import("_entityx");
-    entityx.attr("_entity_manager") = entity_manager_.lock();
-    entityx.attr("_event_manager") = event_manager;
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    throw;
-  }
-}
-
-void PythonSystem::update(ptr<EntityManager> entity_manager, ptr<EventManager> event_manager, double dt) {
-  for (auto entity : entity_manager->entities_with_components<PythonComponent>()) {
-    ptr<PythonComponent> python = entity.component<PythonComponent>();
-
-    try {
-      python->object.attr("update")(dt, frame_);
-    } catch(...) {
-      PyErr_Print();
-      PyErr_Clear();
-      throw;
-    }
-  }
-  frame_++;
-}
-
-void PythonSystem::log_to(LoggerFunction stdout, LoggerFunction stderr) {
-  stdout_ = stdout;
-  stderr_ = stderr;
-}
-
-void PythonSystem::receive(const EntityDestroyedEvent &event) {
-  for (auto proxy : event_proxies_) {
-    proxy->delete_receiver(event.entity);
-  }
-}
-
-void PythonSystem::receive(const ComponentAddedEvent<PythonComponent> &event) {
-  // If the component was created in C++ it won't have a Python object
-  // associated with it. Create one.
-  if (!event.component->object) {
-    py::object module = py::import(event.component->module.c_str());
-    py::object cls = module.attr(event.component->cls.c_str());
-    py::object from_raw_entity = cls.attr("_from_raw_entity");
-    if (py::len(event.component->args) == 0) {
-      event.component->object = from_raw_entity(event.entity.id());
-    } else {
-      py::list args;
-      args.append(event.entity.id());
-      args.extend(event.component->args);
-      event.component->object = from_raw_entity(*py::tuple(args));
-    }
-  }
-
-  for (auto proxy : event_proxies_) {
-    if (proxy->can_send(event.component->object)) {
-      proxy->add_receiver(event.entity);
-    }
-  }
-}
-
-}  // namespace python
-}  // namespace entityx
diff --git a/entityx/python/PythonSystem.h b/entityx/python/PythonSystem.h
deleted file mode 100644 (file)
index d63fa38..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2013 Alec Thomas <alec@swapoff.org>
- * All rights reserved.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution.
- *
- * Author: Alec Thomas <alec@swapoff.org>
- */
-
-#pragma once
-
-// http://docs.python.org/2/extending/extending.html
-#include <Python.h>
-#include <boost/python.hpp>
-#include <boost/function.hpp>
-#include <list>
-#include <vector>
-#include <string>
-#include "entityx/System.h"
-#include "entityx/Entity.h"
-#include "entityx/Event.h"
-#include "entityx/config.h"
-
-// boost::python smart pointer adapter for std::shared_ptr<T>
-#ifdef ENTITYX_NEED_GET_POINTER_SHARED_PTR_SPECIALIZATION
-
-#include <memory>
-
-
-namespace std {
-
-// This may or may not work... it definitely does not work on OSX.
-template <class T> inline T * get_pointer(const std::shared_ptr<T> &p) {
-  return p.get();
-}
-
-}  // namespace std
-
-
-#endif
-
-
-namespace entityx {
-namespace python {
-
-/**
- * An EntityX component that represents a Python script.
- */
-class PythonComponent : public entityx::Component<PythonComponent> {
-public:
-  /**
-   * Create a new PythonComponent from a Python Entity class.
-   *
-   * @param module The Python module where the Entity subclass resides.
-   * @param cls The Class within the module. Must inherit from entityx.Entity.
-   * @param args The *args to pass to the Python constructor.
-   */
-  template <typename ...Args>
-  PythonComponent(const std::string &module, const std::string &cls, Args ... args) : module(module), cls(cls) {
-    unpack_args(args...);
-  }
-
-  /**
-   * Create a new PythonComponent from an existing Python instance.
-   */
-  explicit PythonComponent(boost::python::object object) : object(object) {}
-
-  boost::python::object object;
-  boost::python::list args;
-  const std::string module, cls;
-
-private:
-  template <typename A, typename ...Args>
-  void unpack_args(A &arg, Args ... remainder) {
-    args.append(arg);
-    unpack_args(remainder...);
-  }
-
-  void unpack_args() {}
-};
-
-
-class PythonSystem;
-
-
-/**
- * Proxies C++ EntityX events to Python entities.
- */
-class PythonEventProxy {
-public:
-  friend class PythonSystem;
-
-  /**
-   * Construct a new event proxy.
-   *
-   * @param handler_name The default implementation of can_send() tests for
-   *     the existence of this attribute on an Entity.
-   */
-  explicit PythonEventProxy(const std::string &handler_name) : handler_name(handler_name) {}
-  virtual ~PythonEventProxy() {}
-
-  /**
-   * Return true if this event can be sent to the provided Python entity.
-   *
-   * @param  object The Python entity to test for event delivery.
-   */
-  virtual bool can_send(const boost::python::object &object) const {
-    return PyObject_HasAttrString(object.ptr(), handler_name.c_str());
-  }
-
-protected:
-  std::list<Entity> entities;
-  const std::string handler_name;
-
-private:
-  /**
-   * Add an Entity receiver to this proxy. This is called automatically by PythonSystem.
-   *
-   * @param entity The entity that will receive events.
-   */
-  void add_receiver(Entity entity) {
-    entities.push_back(entity);
-  }
-
-  /**
-   * Delete an Entity receiver. This is called automatically by PythonSystem.
-   *
-   * @param entity The entity that was receiving events.
-   */
-  void delete_receiver(Entity entity) {
-    for (auto i = entities.begin(); i != entities.end(); ++i) {
-      if (entity == *i) {
-        entities.erase(i);
-        break;
-      }
-    }
-  }
-};
-
-
-/**
- * A helper function for class_ to assign a component to an entity.
- */
-template <typename Component>
-void assign_to(ptr<Component> component, ptr<EntityManager> entity_manager, Entity::Id id) {
-  entity_manager->assign<Component>(id, component);
-}
-
-
-/**
- * A helper function for retrieving an existing component associated with an
- * entity.
- */
-template <typename Component>
-ptr<Component> get_component(ptr<EntityManager> entity_manager, Entity::Id id) {
-  return entity_manager->component<Component>(id);
-}
-
-
-/**
- * A PythonEventProxy that broadcasts events to all entities with a matching
- * handler method.
- */
-template <typename Event>
-class BroadcastPythonEventProxy : public PythonEventProxy, public Receiver<BroadcastPythonEventProxy<Event>> {
-public:
-  BroadcastPythonEventProxy(const std::string &handler_name) : PythonEventProxy(handler_name) {}
-  virtual ~BroadcastPythonEventProxy() {}
-
-  void receive(const Event &event) {
-    for (auto entity : entities) {
-      auto py_entity = entity.template component<PythonComponent>();
-      py_entity->object.attr(handler_name.c_str())(event);
-    }
-  }
-};
-
-/**
- * An entityx::System that bridges EntityX and Python.
- *
- * This system handles exposing entityx functionality to Python. The Python
- * support differs in design from the C++ design in the following ways:
- *
- * - Entities contain logic and can receive events.
- * - Systems and Components can not be implemented in Python.
- */
-class PythonSystem : public entityx::System<PythonSystem>, public entityx::Receiver<PythonSystem> {
-public:
-  typedef boost::function<void (const std::string &)> LoggerFunction;
-
-  PythonSystem(ptr<EntityManager> entity_manager);  // NOLINT
-  virtual ~PythonSystem();
-
-  /**
-   * Add system-installed entityx Python path to the interpreter.
-   */
-  void add_installed_library_path();
-
-  /**
-   * Add a Python path to the interpreter.
-   */
-  void add_path(const std::string &path);
-
-  /**
-   * Add a sequence of paths to the interpreter.
-   */
-  template <typename T>
-  void add_paths(const T &paths) {
-    for (auto path : paths) {
-      add_path(path);
-    }
-  }
-
-  /// Return the Python paths the system is configured with.
-  const std::vector<std::string> &python_paths() const {
-    return python_paths_;
-  }
-
-  virtual void configure(ptr<EventManager> event_manager) override;
-  virtual void update(ptr<EntityManager> entities, ptr<EventManager> event_manager, double dt) override;
-
-  /**
-   * Set line-based (not including \n) logger for stdout and stderr.
-   */
-  void log_to(LoggerFunction stdout, LoggerFunction stderr);
-
-  /**
-   * Proxy events of type Event to any Python entity with a handler_name method.
-   */
-  template <typename Event>
-  void add_event_proxy(ptr<EventManager> event_manager, const std::string &handler_name) {
-    ptr<BroadcastPythonEventProxy<Event>> proxy(new BroadcastPythonEventProxy<Event>(handler_name));
-    event_manager->subscribe<Event>(*proxy.get());
-    event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
-  }
-
-  /**
-   * Proxy events of type Event using the given PythonEventProxy implementation.
-   */
-  template <typename Event, typename Proxy>
-  void add_event_proxy(ptr<EventManager> event_manager, ptr<Proxy> proxy) {
-    event_manager->subscribe<Event>(*proxy);
-    event_proxies_.push_back(static_pointer_cast<PythonEventProxy>(proxy));
-  }
-
-  void receive(const EntityDestroyedEvent &event);
-  void receive(const ComponentAddedEvent<PythonComponent> &event);
-
-private:
-  void initialize_python_module();
-
-  weak_ptr<EntityManager> entity_manager_;
-  std::vector<std::string> python_paths_;
-  LoggerFunction stdout_, stderr_;
-  static bool initialized_;
-  std::vector<ptr<PythonEventProxy>> event_proxies_;
-  int frame_ = 0;
-};
-
-}  // namespace python
-}  // namespace entityx
diff --git a/entityx/python/PythonSystem_test.cc b/entityx/python/PythonSystem_test.cc
deleted file mode 100644 (file)
index d4d531c..0000000
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2013 Alec Thomas <alec@swapoff.org>
- * All rights reserved.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution.
- *
- * Author: Alec Thomas <alec@swapoff.org>
- */
-
-// NOTE: MUST be first include. See http://docs.python.org/2/extending/extending.html
-#include <Python.h>
-#include <gtest/gtest.h>
-#include <boost/python.hpp>
-#include <cassert>
-#include <vector>
-#include <string>
-#include <iostream>
-#include "entityx/Entity.h"
-#include "entityx/Event.h"
-#include "entityx/python/PythonSystem.h"
-
-namespace py = boost::python;
-using std::cerr;
-using std::endl;
-using namespace entityx;
-using namespace entityx::python;
-
-
-struct Position : public Component<Position> {
-  Position(float x = 0.0, float y = 0.0) : x(x), y(y) {}
-
-  float x, y;
-};
-
-
-struct Direction : public Component<Direction> {
-  Direction(float x = 0.0, float y = 0.0) : x(x), y(y) {}
-
-  float x, y;
-};
-
-
-struct CollisionEvent : public Event<CollisionEvent> {
-  CollisionEvent(Entity a, Entity b) : a(a), b(b) {}
-
-  Entity a, b;
-};
-
-
-struct CollisionEventProxy : public PythonEventProxy, public Receiver<CollisionEvent> {
-  CollisionEventProxy() : PythonEventProxy("on_collision") {}
-
-  void receive(const CollisionEvent &event) {
-    for (auto entity : entities) {
-      if (entity == event.a || entity == event.b) {
-        auto py_entity = entity.component<PythonComponent>();
-        py_entity->object.attr("on_collision")(event);
-      }
-    }
-  }
-};
-
-
-BOOST_PYTHON_MODULE(entityx_python_test) {
-  py::class_<Position, ptr<Position>>("Position", py::init<py::optional<float, float>>())
-    .def("assign_to", &assign_to<Position>)
-    .def("get_component", &get_component<Position>)
-    .staticmethod("get_component")
-    .def_readwrite("x", &Position::x)
-    .def_readwrite("y", &Position::y);
-
-  py::class_<Direction, ptr<Direction>>("Direction", py::init<py::optional<float, float>>())
-    .def("assign_to", &assign_to<Direction>)
-    .def("get_component", &get_component<Direction>)
-    .staticmethod("get_component")
-    .def_readwrite("x", &Direction::x)
-    .def_readwrite("y", &Direction::y);
-
-  py::class_<CollisionEvent, ptr<CollisionEvent>, py::bases<BaseEvent>>("Collision", py::init<Entity, Entity>())
-    .add_property("a", py::make_getter(&CollisionEvent::a, py::return_value_policy<py::return_by_value>()))
-    .add_property("b", py::make_getter(&CollisionEvent::b, py::return_value_policy<py::return_by_value>()));
-}
-
-
-class PythonSystemTest : public ::testing::Test {
-protected:
-  PythonSystemTest() {
-    assert(PyImport_AppendInittab("entityx_python_test", initentityx_python_test) != -1 && "Failed to initialize entityx_python_test Python module");
-  }
-
-  void SetUp() {
-    ev.reset(new EventManager());
-    em.reset(new EntityManager(ev));
-    system.reset(new PythonSystem(em));
-    system->add_path(ENTITYX_PYTHON_TEST_DATA);
-    if (!initialized) {
-      initentityx_python_test();
-      initialized = true;
-    }
-    system->add_event_proxy<CollisionEvent>(ev, ptr<CollisionEventProxy>(new CollisionEventProxy()));
-    system->configure(ev);
-  }
-
-  void TearDown() {
-    weak_ptr<EventManager> v = ev;
-    weak_ptr<EntityManager> e = em;
-    em->destroy_all();
-    system.reset();
-    em.reset();
-    ev.reset();
-  }
-
-  ptr<PythonSystem> system;
-  ptr<EventManager> ev;
-  ptr<EntityManager> em;
-  static bool initialized;
-};
-
-bool PythonSystemTest::initialized = false;
-
-
-TEST_F(PythonSystemTest, TestSystemUpdateCallsEntityUpdate) {
-  try {
-    Entity e = em->create();
-    auto script = e.assign<PythonComponent>("entityx.tests.update_test", "UpdateTest");
-    ASSERT_FALSE(py::extract<bool>(script->object.attr("updated")));
-    system->update(em, ev, 0.1);
-    ASSERT_TRUE(py::extract<bool>(script->object.attr("updated")));
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestComponentAssignmentCreationInPython) {
-  try {
-    Entity e = em->create();
-    auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
-    ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
-    ASSERT_TRUE(script->object);
-    ASSERT_TRUE(script->object.attr("test_assign_create"));
-    script->object.attr("test_assign_create")();
-    auto position = e.component<Position>();
-    ASSERT_TRUE(static_cast<bool>(position));
-    ASSERT_EQ(position->x, 1.0);
-    ASSERT_EQ(position->y, 2.0);
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestComponentAssignmentCreationInCpp) {
-  try {
-    Entity e = em->create();
-    e.assign<Position>(2, 3);
-    auto script = e.assign<PythonComponent>("entityx.tests.assign_test", "AssignTest");
-    ASSERT_TRUE(static_cast<bool>(e.component<Position>()));
-    ASSERT_TRUE(script->object);
-    ASSERT_TRUE(script->object.attr("test_assign_existing"));
-    script->object.attr("test_assign_existing")();
-    auto position = e.component<Position>();
-    ASSERT_TRUE(static_cast<bool>(position));
-    ASSERT_EQ(position->x, 3.0);
-    ASSERT_EQ(position->y, 4.0);
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestEntityConstructorArgs) {
-  try {
-    Entity e = em->create();
-    auto script = e.assign<PythonComponent>("entityx.tests.constructor_test", "ConstructorTest", 4.0, 5.0);
-    auto position = e.component<Position>();
-    ASSERT_TRUE(static_cast<bool>(position));
-    ASSERT_EQ(position->x, 4.0);
-    ASSERT_EQ(position->y, 5.0);
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestEventDelivery) {
-  try {
-    Entity f = em->create();
-    Entity e = em->create();
-    Entity g = em->create();
-    auto scripte = e.assign<PythonComponent>("entityx.tests.event_test", "EventTest");
-    auto scriptf = f.assign<PythonComponent>("entityx.tests.event_test", "EventTest");
-    auto scriptg = g.assign<PythonComponent>("entityx.tests.event_test", "EventTest");
-    ASSERT_FALSE(scripte->object.attr("collided"));
-    ASSERT_FALSE(scriptf->object.attr("collided"));
-    ev->emit<CollisionEvent>(f, g);
-    ASSERT_TRUE(scriptf->object.attr("collided"));
-    ASSERT_FALSE(scripte->object.attr("collided"));
-    ev->emit<CollisionEvent>(e, f);
-    ASSERT_TRUE(scriptf->object.attr("collided"));
-    ASSERT_TRUE(scripte->object.attr("collided"));
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestDeepEntitySubclass) {
-  try {
-    Entity e = em->create();
-    auto script = e.assign<PythonComponent>("entityx.tests.deep_subclass_test", "DeepSubclassTest");
-    ASSERT_TRUE(script->object.attr("test_deep_subclass"));
-    script->object.attr("test_deep_subclass")();
-
-    Entity e2 = em->create();
-    auto script2 = e2.assign<PythonComponent>("entityx.tests.deep_subclass_test", "DeepSubclassTest2");
-    ASSERT_TRUE(script2->object.attr("test_deeper_subclass"));
-    script2->object.attr("test_deeper_subclass")();
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestEntityCreationFromPython) {
-  try {
-    py::object test = py::import("entityx.tests.create_entities_from_python_test");
-    test.attr("create_entities_from_python_test")();
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
-
-
-TEST_F(PythonSystemTest, TestEventEmissionFromPython) {
-  try {
-    struct CollisionReceiver : public Receiver<CollisionReceiver> {
-      void receive(const CollisionEvent &event) {
-        a = event.a;
-        b = event.b;
-      }
-
-      Entity a, b;
-    };
-
-    CollisionReceiver receiver;
-    ev->subscribe<CollisionEvent>(receiver);
-
-    ASSERT_FALSE(receiver.a);
-    ASSERT_FALSE(receiver.b);
-
-    py::object test = py::import("entityx.tests.event_emit_test");
-    test.attr("emit_collision_from_python")();
-
-    ASSERT_TRUE(receiver.a);
-    ASSERT_TRUE(receiver.b);
-  } catch(...) {
-    PyErr_Print();
-    PyErr_Clear();
-    ASSERT_FALSE(true) << "Python exception.";
-  }
-}
diff --git a/entityx/python/README.md b/entityx/python/README.md
deleted file mode 100644 (file)
index cf83ab5..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-# Python Scripting System for EntityX (α Alpha)
-
-This system adds the ability to extend entity logic with Python scripts. The goal is to allow ad-hoc behaviour to be assigned to entities, in contract to the more pure entity-component system approach.
-
-## Limitations
-
-Planned features that are currently unimplemented:
-
-- Emitting events from Python.
-
-## Design
-
-- Python scripts are attached to entities via `PythonComponent`.
-- Systems and components can not be created from Python, primarily for performance reasons.
-- Events are proxied directly to Python entities via `PythonEventProxy` objects.
-    - Each event to be handled in Python must have an associated `PythonEventProxy`implementation.
-    - As a convenience `BroadcastPythonEventProxy<Event>(handler_method)` can be used. It will broadcast events to all `PythonComponent` entities with a `<handler_method>`.
-- `PythonSystem` manages scripted entity lifecycle and event delivery.
-
-## Summary
-
-To add scripting support to your system, something like the following steps should be followed:
-
-1. Expose C++ `Component` and `Event` classes to Python with `BOOST_PYTHON_MODULE`.
-2. Initialize the module with `PyImport_AppendInittab`.
-3. Create a Python package.
-4. Add classes to the package, inheriting from `entityx.Entity` and using the `entityx.Component` descriptor to assign components.
-5. Create a `PythonSystem`, passing in the list of paths to add to Python's import search path.
-6. Optionally attach any event proxies.
-7. Create an entity and associate it with a Python script by assigning `PythonComponent`, passing it the package name, class name, and any constructor arguments.
-8. When finished, call `EntityManager::destroy_all()`.
-
-## Interfacing with Python
-
-`entityx::python` primarily uses standard `boost::python` to interface with Python, with some helper classes and functions.
-
-### Exposing C++ Components to Python
-
-In most cases, this should be pretty simple. Given a component, provide a `boost::python` class definition wrapped in `entityx::ptr<T>`, with two extra methods defined with EntityX::Python helper functions `assign_to<Component>` and `get_component<Component>`. These are used from Python to assign Python-created components to an entity and to retrieve existing components from an entity, respectively.
-
-Here's an example:
-
-```c++
-namespace py = boost::python;
-using namespace entityx;
-using namespace entityx::python;
-
-
-struct Position : public Component<Position> {
-  Position(float x = 0.0, float y = 0.0) : x(x), y(y) {}
-
-  float x, y;
-};
-
-void export_position_to_python() {
-  py::class_<PythonPosition, ptr<PythonPosition>>("Position", py::init<py::optional<float, float>>())
-    .def("assign_to", &assign_to<Position>)          // Allows this component to be assigned to an entity
-    .def("get_component", &get_component<Position>)  // Allows this component to be retrieved from an entity.
-    .staticmethod("get_component")                   // (as above)
-    .def_readwrite("x", &PythonPosition::x)
-    .def_readwrite("y", &PythonPosition::y);
-}
-
-BOOST_PYTHON_MODULE(mygame) {
-  export_position_to_python();
-}
-```
-
-### Delivering events to Python entities
-
-Unlike in C++, where events are typically handled by systems, EntityX::Python
-explicitly provides support for sending events to entities. To bridge this gap
-use the `PythonEventProxy` class to receive C++ events and proxy them to
-Python entities.
-
-The class takes a single parameter, which is the name of the attribute on a
-Python entity. If this attribute exists, the entity will be added to
-`PythonEventProxy::entities (std::list<Entity>)`, so that matching entities
-will be accessible from any event handlers.
-
-This checking is performed in `PythonEventProxy::can_send()`, and can be
-overridden, but further checking can also be done in the event `receive()`
-method.
-
-A helper template class called `BroadcastPythonEventProxy<Event>` is provided
-that will broadcast events to any entity with the corresponding handler method.
-
-To implement more refined logic, subclass `PythonEventProxy` and operate on
-the protected member `entities`. Here's a collision example, where the proxy
-only delivers collision events to the colliding entities themselves:
-
-```c++
-struct CollisionEvent : public Event<CollisionEvent> {
-  CollisionEvent(Entity a, Entity b) : a(a), b(b) {}
-
-  Entity a, b;
-};
-
-struct CollisionEventProxy : public PythonEventProxy, public Receiver<CollisionEvent> {
-  CollisionEventProxy() : PythonEventProxy("on_collision") {}
-
-  void receive(const CollisionEvent &event) {
-    // "entities" is a protected data member, populated by
-    // PythonSystem, with Python entities that pass can_send().
-    for (auto entity : entities) {
-      auto py_entity = entity.template component<PythonComponent>();
-      if (entity == event.a || entity == event.b) {
-        py_entity->object.attr(handler_name.c_str())(event);
-      }
-    }
-  }
-};
-
-void export_collision_event_to_python() {
-  py::class_<CollisionEvent, ptr<CollisionEvent>, py::bases<BaseEvent>>("Collision", py::init<Entity, Entity>())
-    .def_readonly("a", &CollisionEvent::a)
-    .def_readonly("b", &CollisionEvent::b);
-}
-
-
-BOOST_PYTHON_MODULE(mygame) {
-  export_position_to_python();
-  export_collision_event_to_python();
-}
-```
-
-
-### Sending events from Python
-
-This is relatively straight forward. Once you have exported a C++ event to Python:
-
-```python
-from entityx import Entity, emit
-from mygame import Collision
-
-
-class AnEntity(Entity): pass
-
-
-emit(Collision(AnEntity(), AnEntity()))
-```
-
-
-### Initialization
-
-Finally, initialize the `mygame` module once, before using `PythonSystem`, with something like this:
-
-```c++
-// This should only be performed once, at application initialization time.
-CHECK(PyImport_AppendInittab("mygame", initmygame) != -1)
-  << "Failed to initialize mygame Python module";
-```
-
-Then create and destroy `PythonSystem` as necessary:
-
-```c++
-// Initialize the PythonSystem.
-vector<string> paths;
-paths.push_back(MYGAME_PYTHON_PATH);
-// +any other Python paths...
-ptr<PythonSystem> python(new PythonSystem(paths));
-
-// Add any Event proxies.
-python->add_event_proxy<CollisionEvent>(ev, ptr<CollisionEventProxy>(new CollisionEventProxy()));
-```
diff --git a/entityx/python/entityx/__init__.py b/entityx/python/entityx/__init__.py
deleted file mode 100644 (file)
index 339c90b..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-import _entityx
-
-
-"""These classes provide a convenience layer on top of the raw entityx::python
-primitives.
-
-They allow you to declare your entities and components in an intuitive way:
-
-    class Player(Entity):
-        position = Component(Position)
-        direction = Component(Direction)
-        sprite = Component(Sprite, 'player.png')  # Sprite component with constructor argument
-
-        def update(self, dt, frame):
-            self.position.x += self.direction.x * dt
-            self.position.x += self.direction.y * dt
-
-Note that components assigned from C++ must be assigned prior to assigning
-PythonComponent, otherwise they will be created by the Entity constructor.
-"""
-
-
-__all__ = ['Entity', 'Component']
-
-
-class Component(object):
-    """A field that manages Component creation/retrieval.
-
-    Use like so:
-
-    class Player(Entity):
-        position = Component(Position)
-
-        def move_to(self, x, y):
-            self.position.x = x
-            self.position.y = y
-    """
-    def __init__(self, cls, *args, **kwargs):
-        self._cls = cls
-        self._args = args
-        self._kwargs = kwargs
-
-    def _build(self, entity_id):
-        component = self._cls.get_component(_entityx._entity_manager, entity_id)
-        if not component:
-            component = self._cls(*self._args, **self._kwargs)
-            component.assign_to(_entityx._entity_manager, entity_id)
-        return component
-
-
-class EntityMetaClass(_entityx.Entity.__class__):
-    """Collect registered components from class attributes.
-
-    This is done at class creation time to reduce entity creation overhead.
-    """
-
-    def __new__(cls, name, bases, dct):
-        dct['_components'] = components = {}
-        # Collect components from base classes
-        for base in bases:
-            if '_components' in base.__dict__:
-                components.update(base.__dict__['_components'])
-        # Collect components
-        for key, value in dct.items():
-            if isinstance(value, Component):
-                components[key] = value
-        return type.__new__(cls, name, bases, dct)
-
-
-class Entity(_entityx.Entity):
-    """Base Entity class.
-
-    Python Enitities differ in semantics from C++ components, in that they
-    contain logic, receive events, and so on.
-    """
-
-    __metaclass__ = EntityMetaClass
-
-    def __new__(cls, *args, **kwargs):
-        entity_id = kwargs.pop('entity_id', None)
-        self = _entityx.Entity.__new__(cls)
-        if entity_id is None:
-            entity_id = _entityx._entity_manager.configure(self)
-        _entityx.Entity.__init__(self, _entityx._entity_manager, entity_id)
-        for k, v in self._components.items():
-            setattr(self, k, v._build(self._entity_id))
-        return self
-
-    def __init__(self):
-        """Default constructor."""
-
-    def __repr__(self):
-        return '<%s.%s %d.%d>' % (self.__class__.__module__, self.__class__.__name__, self._entity_id.index, self._entity_id.version)
-
-    @classmethod
-    def _from_raw_entity(cls, entity_id, *args, **kwargs):
-        """Create a new Entity from a raw entity.
-
-        This is called from C++.
-        """
-        self = Entity.__new__(cls, entity_id=entity_id)
-        cls.__init__(self, *args, **kwargs)
-        return self
-
-
-def emit(event):
-    """Emit an event.
-
-    :param event: A Python-exposed C++ subclass of entityx::BaseEvent.
-    """
-    return _entityx._event_manager.emit(event)
diff --git a/entityx/python/entityx/tests/__init__.py b/entityx/python/entityx/tests/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/entityx/python/entityx/tests/assign_test.py b/entityx/python/entityx/tests/assign_test.py
deleted file mode 100644 (file)
index 670d9b9..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-from entityx import Entity, Component
-from entityx_python_test import Position
-
-
-class AssignTest(Entity):
-    position = Component(Position)
-
-    def test_assign_create(self):
-        assert self.position.x == 0.0, self.position.x
-        assert self.position.y == 0.0, self.position.y
-        self.position.x = 1
-        self.position.y = 2
-
-    def test_assign_existing(self):
-        assert self.position.x == 2, self.position.x
-        assert self.position.y == 3, self.position.y
-        self.position.x += 1
-        self.position.y += 1
diff --git a/entityx/python/entityx/tests/constructor_test.py b/entityx/python/entityx/tests/constructor_test.py
deleted file mode 100644 (file)
index 6dd62de..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-from entityx import Entity, Component
-from entityx_python_test import Position
-
-
-class ConstructorTest(Entity):
-    position = Component(Position)
-
-    def __init__(self, x, y):
-        self.position.x = x
-        self.position.y = y
diff --git a/entityx/python/entityx/tests/create_entities_from_python_test.py b/entityx/python/entityx/tests/create_entities_from_python_test.py
deleted file mode 100644 (file)
index 8f8f3a4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import entityx
-from entityx_python_test import Position
-
-
-class EntityA(entityx.Entity):
-    position = entityx.Component(Position, 1, 2)
-
-    def __init__(self, x=None, y=None):
-        if x is not None:
-            self.position.x = x
-        if y is not None:
-            self.position.y = y
-
-
-def create_entities_from_python_test():
-    a = EntityA()
-    assert a._entity_id.index == 0
-    assert a.position.x == 1.0
-    assert a.position.y == 2.0
-
-    b = EntityA()
-    assert b._entity_id.index == 1
-
-    a.destroy()
-    c = EntityA()
-    # Reuse destroyed index of "a".
-    assert c._entity_id.index == 0
-    # However, version is different
-    assert a._entity_id.id != c._entity_id.id and c._entity_id.id > a._entity_id.id
-
-    d = EntityA(2.0, 3.0)
-    assert d.position.x == 2.0
-    assert d.position.y == 3.0
diff --git a/entityx/python/entityx/tests/deep_subclass_test.py b/entityx/python/entityx/tests/deep_subclass_test.py
deleted file mode 100644 (file)
index 801b487..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-from entityx import Entity, Component
-from entityx_python_test import Position, Direction
-
-
-class BaseEntity(Entity):
-    direction = Component(Direction)
-
-
-class DeepSubclassTest(BaseEntity):
-    position = Component(Position)
-
-    def test_deep_subclass(self):
-        assert self.direction
-        assert self.position
-
-
-class DeepSubclassTest2(DeepSubclassTest):
-    position2 = Component(Position)
-
-    def test_deeper_subclass(self):
-        assert self.direction
-        assert self.position
-        assert self.position2
-        assert self.position.x == self.position2.x and self.position.y == self.position2.y
-        self.position.x += 1
-        assert self.position.x == self.position2.x and self.position.y == self.position2.y
diff --git a/entityx/python/entityx/tests/event_emit_test.py b/entityx/python/entityx/tests/event_emit_test.py
deleted file mode 100644 (file)
index 4696e26..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from entityx import Entity, emit
-from entityx_python_test import Collision
-
-
-class AnEntity(Entity):
-    pass
-
-
-def emit_collision_from_python():
-    a = AnEntity()
-    b = AnEntity()
-    collision = Collision(a, b)
-    emit(collision)
diff --git a/entityx/python/entityx/tests/event_test.py b/entityx/python/entityx/tests/event_test.py
deleted file mode 100644 (file)
index 8edf8c5..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from entityx import Entity
-
-
-class EventTest(Entity):
-    collided = False
-
-    def on_collision(self, event):
-        assert event.a
-        assert event.b
-        assert event.a == self or event.b == self
-        self.collided = True
diff --git a/entityx/python/entityx/tests/update_test.py b/entityx/python/entityx/tests/update_test.py
deleted file mode 100644 (file)
index 7585aa6..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-import entityx
-
-
-class UpdateTest(entityx.Entity):
-    updated = False
-
-    def update(self, dt, frame):
-        self.updated = True
diff --git a/entityx/python/setup.py b/entityx/python/setup.py
deleted file mode 100644 (file)
index 50e2b03..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-try:
-    from distribute import setup
-except ImportError:
-    from setuptools import setup
-
-setup(
-    name='entityx',
-    version='0.0.1',
-    packages=['entityx'],
-    license='MIT',
-    description='EntityX Entity-Component Framework Python bindings',
-    )