mirror of
https://github.com/boostorg/python.git
synced 2026-01-22 05:22:45 +00:00
* Updated to new handle_exception() idiom for boost::python
* Made Cygwin archiving reliable, even when the user supplies a path with backslashes ---------------------------------------------------------------------- Modified Files: tools/build/gcc-tools.jam tools/build/new/boost-build.jam boost/python/detail/config.hpp libs/python/build/Jamfile libs/python/example/do_it_yourself_convts.cpp libs/python/example/dvect.cpp libs/python/example/example1.cpp libs/python/example/getting_started1.cpp libs/python/example/getting_started2.cpp libs/python/example/ivect.cpp libs/python/example/nested.cpp libs/python/example/noncopyable_export.cpp libs/python/example/noncopyable_import.cpp libs/python/example/pickle1.cpp libs/python/example/pickle2.cpp libs/python/example/pickle3.cpp libs/python/example/richcmp1.cpp libs/python/example/richcmp2.cpp libs/python/example/richcmp3.cpp libs/python/example/rwgk1.cpp libs/python/example/simple_vector.cpp libs/python/test/comprehensive.cpp Added Files: libs/python/example/rwgk2.cpp libs/python/example/rwgk3.cpp ---------------------------------------------------------------------- [SVN r11705]
This commit is contained in:
@@ -136,7 +136,7 @@ lib libboost_python_d : ../src/$(CPP_SOURCES).cpp
|
||||
# Declare a boost python module. Return a list of the DLL files generated.
|
||||
rule boost-python
|
||||
{
|
||||
local debug ;
|
||||
local debug = "" ;
|
||||
if ( <define>BOOST_DEBUG_PYTHON in $(3) ) || ( debug-python in $(BUILD) )
|
||||
{
|
||||
debug = _d ;
|
||||
@@ -203,7 +203,9 @@ rule python-test-target # test-target : sources :
|
||||
{
|
||||
python-runtest-aux $(<) : $(>) ;
|
||||
Clean clean : $(<) ; # remove the test-target as part of any clean operation
|
||||
type-DEPENDS test : $(<) ;
|
||||
local debug = [ SUBST $(<:B) (_d)$ $1 ] ;
|
||||
debug ?= "" ;
|
||||
type-DEPENDS test$(debug) : $(<) ;
|
||||
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
||||
}
|
||||
actions python-test-target bind PYTHON
|
||||
@@ -249,6 +251,7 @@ rule python-runtest-aux # target : sources
|
||||
$(gLOCATE($(>[1]))) # location of python test file
|
||||
$(gRUN_PATH($(<))) # location of module dependencies
|
||||
[ join-path $(TOP) libs python test ] # location of doctest
|
||||
$(>:D) # directory of python driver file(s)
|
||||
$(PYTHONPATH) # base PYTHONPATH from environment
|
||||
: $(SPLITPATH) ] ; # platform path separator
|
||||
|
||||
|
||||
@@ -107,8 +107,6 @@ BOOST_PYTHON_END_CONVERSION_NAMESPACE
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(do_it_yourself_convts)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("do_it_yourself_convts");
|
||||
|
||||
@@ -120,9 +118,4 @@ BOOST_PYTHON_MODULE_INIT(do_it_yourself_convts)
|
||||
// Add the member functions.
|
||||
ixset_class.def(&IndexingSet::add, "add");
|
||||
ixset_class.def(&IndexingSet::get, "get");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*)
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(dvect)
|
||||
{
|
||||
try
|
||||
{
|
||||
python::module_builder this_module("dvect");
|
||||
|
||||
python::class_builder<vects::dvect> dvect_class(this_module, "dvect");
|
||||
@@ -47,10 +45,4 @@ BOOST_PYTHON_MODULE_INIT(dvect)
|
||||
|
||||
# include "dvect_defs.cpp"
|
||||
# include "ivect_defs.cpp"
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,32 +16,21 @@ namespace hello {
|
||||
|
||||
// Python requires an exported function called init<module-name> in every
|
||||
// extension module. This is where we build the module contents.
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void inithello()
|
||||
BOOST_PYTHON_MODULE_INIT(hello)
|
||||
{
|
||||
try
|
||||
{
|
||||
// create an object representing this extension module
|
||||
boost::python::module_builder hello("hello");
|
||||
// create an object representing this extension module
|
||||
boost::python::module_builder hello("hello");
|
||||
|
||||
// Create the Python type object for our extension class
|
||||
boost::python::class_builder<hello::world> world_class(hello, "world");
|
||||
// Create the Python type object for our extension class
|
||||
boost::python::class_builder<hello::world> world_class(hello, "world");
|
||||
|
||||
// Add the __init__ function
|
||||
world_class.def(boost::python::constructor<int>());
|
||||
// Add a regular member function
|
||||
world_class.def(&hello::world::get, "get");
|
||||
// Add the __init__ function
|
||||
world_class.def(boost::python::constructor<int>());
|
||||
// Add a regular member function
|
||||
world_class.def(&hello::world::get, "get");
|
||||
|
||||
// Add a regular function to the module
|
||||
hello.def(hello::length, "length");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
boost::python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
// Add a regular function to the module
|
||||
hello.def(hello::length, "length");
|
||||
}
|
||||
|
||||
// Win32 DLL boilerplate
|
||||
|
||||
@@ -16,17 +16,10 @@ namespace python = boost::python;
|
||||
// extension module. This is where we build the module contents.
|
||||
BOOST_PYTHON_MODULE_INIT(getting_started1)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("getting_started1");
|
||||
|
||||
// Add regular functions to the module.
|
||||
this_module.def(greet, "greet");
|
||||
this_module.def(square, "square");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace python = boost::python;
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(getting_started2)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("getting_started2");
|
||||
|
||||
@@ -44,9 +42,4 @@ BOOST_PYTHON_MODULE_INIT(getting_started2)
|
||||
|
||||
// Even better, invite() can also be made a member of hello_class!!!
|
||||
hello_class.def(invite, "invite");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@ extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*)
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(ivect)
|
||||
{
|
||||
try
|
||||
{
|
||||
python::module_builder this_module("ivect");
|
||||
|
||||
python::class_builder<vects::ivect> ivect_class(this_module, "ivect");
|
||||
@@ -47,10 +45,5 @@ BOOST_PYTHON_MODULE_INIT(ivect)
|
||||
|
||||
# include "dvect_defs.cpp"
|
||||
# include "ivect_defs.cpp"
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,6 @@ namespace {
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(nested)
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::python::module_builder this_module("nested");
|
||||
this_module.def(show_nested_tuples, "show_nested_tuples");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
boost::python::handle_exception();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*)
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(noncopyable_export)
|
||||
{
|
||||
try
|
||||
{
|
||||
python::module_builder this_module("noncopyable_export");
|
||||
|
||||
python::class_builder<store> store_class(this_module, "store");
|
||||
@@ -27,9 +25,4 @@ BOOST_PYTHON_MODULE_INIT(noncopyable_export)
|
||||
|
||||
store_class.def(python::constructor<int>());
|
||||
store_class.def(&store::recall, "recall");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ extern "C" void (*old_translator)(unsigned int, EXCEPTION_POINTERS*)
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(noncopyable_import)
|
||||
{
|
||||
try
|
||||
{
|
||||
python::module_builder this_module("noncopyable_import");
|
||||
|
||||
python::import_converters<store>
|
||||
@@ -44,9 +42,4 @@ BOOST_PYTHON_MODULE_INIT(noncopyable_import)
|
||||
// However, to keep this example simple, we only define a
|
||||
// module-level function.
|
||||
this_module.def(add_stores, "add_stores");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,6 @@ namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(pickle1)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("pickle1");
|
||||
|
||||
@@ -56,9 +54,4 @@ BOOST_PYTHON_MODULE_INIT(pickle1)
|
||||
|
||||
// Support for pickle.
|
||||
world_class.def(world_getinitargs, "__getinitargs__");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,8 +73,6 @@ namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(pickle2)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("pickle2");
|
||||
|
||||
@@ -92,9 +90,4 @@ BOOST_PYTHON_MODULE_INIT(pickle2)
|
||||
world_class.def(world_getinitargs, "__getinitargs__");
|
||||
world_class.def(world_getstate, "__getstate__");
|
||||
world_class.def(world_setstate, "__setstate__");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,6 @@ namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(pickle3)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("pickle3");
|
||||
|
||||
@@ -85,11 +83,6 @@ BOOST_PYTHON_MODULE_INIT(pickle3)
|
||||
world_class.def_raw(world_getstate, "__getstate__");
|
||||
world_class.def_raw(world_setstate, "__setstate__");
|
||||
world_class.getstate_manages_dict();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -77,11 +77,8 @@ namespace {
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(richcmp1)
|
||||
{
|
||||
try {
|
||||
boost::python::module_builder this_module("richcmp1");
|
||||
// The actual work is done in a separate function in order
|
||||
// to suppress a bogus VC60 warning.
|
||||
init_module(this_module);
|
||||
}
|
||||
catch (...) { boost::python::handle_exception(); }
|
||||
}
|
||||
|
||||
@@ -55,11 +55,8 @@ namespace {
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(richcmp2)
|
||||
{
|
||||
try {
|
||||
boost::python::module_builder this_module("richcmp2");
|
||||
// The actual work is done in a separate function in order
|
||||
// to suppress a bogus VC60 warning.
|
||||
init_module(this_module);
|
||||
}
|
||||
catch (...) { boost::python::handle_exception(); }
|
||||
}
|
||||
|
||||
@@ -168,11 +168,8 @@ namespace {
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(richcmp3)
|
||||
{
|
||||
try {
|
||||
boost::python::module_builder this_module("richcmp3");
|
||||
// The actual work is done in a separate function in order
|
||||
// to suppress a bogus VC60 warning.
|
||||
init_module(this_module);
|
||||
}
|
||||
catch (...) { boost::python::handle_exception(); }
|
||||
}
|
||||
|
||||
@@ -13,29 +13,12 @@ namespace python = boost::python;
|
||||
|
||||
// Python requires an exported function called init<module-name> in every
|
||||
// extension module. This is where we build the module contents.
|
||||
extern "C"
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void initrwgk1()
|
||||
BOOST_PYTHON_MODULE_INIT(rwgk1)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
python::module_builder this_module("rwgk1");
|
||||
|
||||
// Add regular functions to the module.
|
||||
this_module.def(greet, "greet");
|
||||
this_module.def(square, "square");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
// Win32 DLL boilerplate
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; }
|
||||
#endif // _WIN32
|
||||
|
||||
50
example/rwgk2.cpp
Normal file
50
example/rwgk2.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
// A friendly class.
|
||||
class world
|
||||
{
|
||||
private:
|
||||
std::string country;
|
||||
public:
|
||||
world(const std::string& country) { this->country = country; }
|
||||
std::string greet() const { return "Hello from " + country + "!"; }
|
||||
};
|
||||
|
||||
// A function taking a world object as an argument.
|
||||
std::string invite(const world& w) {
|
||||
return w.greet() + " Please come soon!";
|
||||
}
|
||||
}
|
||||
|
||||
#include <py_cpp/class_wrapper.h>
|
||||
|
||||
// Python requires an exported function called init<module-name> in every
|
||||
// extension module. This is where we build the module contents.
|
||||
BOOST_PYTHON_MODULE_INIT(example2)
|
||||
{
|
||||
// Create an object representing this extension module.
|
||||
py::Module this_module("example2");
|
||||
|
||||
// Create the Python type object for our extension class.
|
||||
py::ClassWrapper<world> world_class(this_module, "world");
|
||||
|
||||
// Add the __init__ function.
|
||||
world_class.def(py::Constructor<std::string>());
|
||||
// Add a regular member function.
|
||||
world_class.def(&world::greet, "greet");
|
||||
|
||||
// Add invite() as a regular function to the module.
|
||||
this_module.def(invite, "invite");
|
||||
|
||||
// Even better, invite() can also be made a member of world_class!!!
|
||||
world_class.def(invite, "invite");
|
||||
}
|
||||
|
||||
// Win32 DLL boilerplate
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; }
|
||||
#endif // _WIN32
|
||||
101
example/rwgk3.cpp
Normal file
101
example/rwgk3.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <py_cpp/class_wrapper.h>
|
||||
#include <py_cpp/objects.h>
|
||||
|
||||
#define rangei(n) for (int i = 0; i < n; i++)
|
||||
|
||||
namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
// A wrapper is used to define additional constructors.
|
||||
//
|
||||
struct vector_double_wrapper: std::vector<double>
|
||||
{
|
||||
// Tell the compiler how to convert a base class object to
|
||||
// this wrapper object.
|
||||
vector_double_wrapper(PyObject*, const std::vector<double>& vd)
|
||||
: std::vector<double>(vd) {}
|
||||
|
||||
vector_double_wrapper(PyObject* self)
|
||||
: std::vector<double>() {}
|
||||
|
||||
vector_double_wrapper(PyObject* self, const int n)
|
||||
: std::vector<double>(n) {}
|
||||
|
||||
vector_double_wrapper(PyObject* self, py::Tuple tuple)
|
||||
: std::vector<double>(tuple.size())
|
||||
{
|
||||
std::vector<double>::iterator vd = begin();
|
||||
rangei(tuple.size())
|
||||
vd[i] = from_python(tuple[i].get(), py::Type<double>()); // GCC BUG
|
||||
}
|
||||
};
|
||||
|
||||
double getitem(const std::vector<double>& vd, const std::size_t key) {
|
||||
return vd[key];
|
||||
}
|
||||
|
||||
void setitem(std::vector<double>& vd, const std::size_t key,
|
||||
const double &d) {
|
||||
std::vector<double>::iterator vditer = vd.begin();
|
||||
vditer[key] = d;
|
||||
}
|
||||
|
||||
void delitem(std::vector<double>& vd, const std::size_t key) {
|
||||
std::vector<double>::iterator vditer = vd.begin();
|
||||
vd.erase(&vditer[key]);
|
||||
}
|
||||
|
||||
// Convert vector_double to a regular Python tuple.
|
||||
//
|
||||
py::Tuple as_tuple(const std::vector<double>& vd)
|
||||
{
|
||||
py::Tuple t(vd.size());
|
||||
rangei(vd.size()) t.set_item(i, py::Ptr(py::to_python(vd[i]))); // GCC BUG
|
||||
return t;
|
||||
}
|
||||
|
||||
// Function returning a vector_double object to Python.
|
||||
//
|
||||
std::vector<double> foo(const int n)
|
||||
{
|
||||
std::vector<double> vd(n);
|
||||
std::vector<double>::iterator vditer = vd.begin();
|
||||
rangei(n) vditer[i] = double(i);
|
||||
return vd;
|
||||
}
|
||||
|
||||
// Same as foo(), but avoid copying on return.
|
||||
//
|
||||
std::auto_ptr<std::vector<double> > bar(const int n)
|
||||
{
|
||||
std::auto_ptr<std::vector<double> > vdptr(new std::vector<double>(n));
|
||||
std::vector<double>::iterator vditer = vdptr->begin();
|
||||
rangei(n) vditer[i] = double(10 * i);
|
||||
return vdptr;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(example3)
|
||||
{
|
||||
py::Module this_module("example3");
|
||||
|
||||
py::ClassWrapper<std::vector<double>, vector_double_wrapper>
|
||||
vector_double(this_module, "vector_double");
|
||||
|
||||
vector_double.def(py::Constructor<>());
|
||||
vector_double.def(py::Constructor<const int>());
|
||||
vector_double.def(py::Constructor<py::Tuple>());
|
||||
vector_double.def(&std::vector<double>::size, "__len__");
|
||||
vector_double.def(getitem, "__getitem__");
|
||||
vector_double.def(setitem, "__setitem__");
|
||||
vector_double.def(delitem, "__delitem__");
|
||||
vector_double.def(as_tuple, "as_tuple");
|
||||
|
||||
this_module.def(foo, "foo");
|
||||
this_module.def(bar, "bar");
|
||||
}
|
||||
|
||||
// Win32 DLL boilerplate
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID) { return 1; }
|
||||
#endif // _WIN32
|
||||
@@ -85,8 +85,6 @@ namespace { // Avoid cluttering the global namespace.
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(simple_vector)
|
||||
{
|
||||
try
|
||||
{
|
||||
python::module_builder this_module("simple_vector");
|
||||
|
||||
python::class_builder<std::vector<double>, vector_double_wrapper>
|
||||
@@ -103,9 +101,4 @@ BOOST_PYTHON_MODULE_INIT(simple_vector)
|
||||
|
||||
this_module.def(foo, "foo");
|
||||
this_module.def(bar, "bar");
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
python::handle_exception(); // Deal with the exception for Python
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
# endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# define BOOST_PYTHON_MODULE_INIT(name) extern "C" __declspec(dllexport) void init##name()
|
||||
# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" __declspec(dllexport) void init##name() { boost::python::handle_exception(init_module_##name); } void init_module_##name()
|
||||
#else
|
||||
# define BOOST_PYTHON_MODULE_INIT(name) extern "C" void init##name()
|
||||
# define BOOST_PYTHON_MODULE_INIT(name) void init_module_##name(); extern "C" void init##name() { boost::python::handle_exception(init_module_##name); } void init_module_##name()
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_DWA052200_H_
|
||||
|
||||
@@ -1128,7 +1128,7 @@ PyObject* raw(const boost::python::tuple& args, const boost::python::dictionary&
|
||||
return BOOST_PYTHON_CONVERSION::to_python(first->i_ + second + third + fourth);
|
||||
}
|
||||
|
||||
void init_module()
|
||||
BOOST_PYTHON_MODULE_INIT(boost_python_test)
|
||||
{
|
||||
boost::python::module_builder boost_python_test("boost_python_test");
|
||||
init_module(boost_python_test);
|
||||
@@ -1137,11 +1137,6 @@ void init_module()
|
||||
boost_python_test.add(new boost::python::meta_class<boost::python::instance>);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE_INIT(boost_python_test)
|
||||
{
|
||||
boost::python::handle_exception((void (*)())bpl_test::init_module);
|
||||
}
|
||||
|
||||
CompareIntPairPythonClass::CompareIntPairPythonClass(boost::python::module_builder& m)
|
||||
: boost::python::class_builder<CompareIntPair>(m, "CompareIntPair")
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user