Skip to content
Projeler
Gruplar
Parçacıklar
Yardım
Yükleniyor...
Oturum aç / Kaydol
Gezinmeyi değiştir
D
django
Proje
Proje
Ayrıntılar
Etkinlik
Cycle Analytics
Depo (repository)
Depo (repository)
Dosyalar
Kayıtlar (commit)
Dallar (branch)
Etiketler
Katkıda bulunanlar
Grafik
Karşılaştır
Grafikler
Konular (issue)
0
Konular (issue)
0
Liste
Pano
Etiketler
Kilometre Taşları
Birleştirme (merge) Talepleri
0
Birleştirme (merge) Talepleri
0
CI / CD
CI / CD
İş akışları (pipeline)
İşler
Zamanlamalar
Grafikler
Paketler
Paketler
Wiki
Wiki
Parçacıklar
Parçacıklar
Üyeler
Üyeler
Collapse sidebar
Close sidebar
Etkinlik
Grafik
Grafikler
Yeni bir konu (issue) oluştur
İşler
Kayıtlar (commit)
Konu (issue) Panoları
Kenar çubuğunu aç
Batuhan Osman TASKAYA
django
Commits
b01ceae8
Kaydet (Commit)
b01ceae8
authored
Ara 15, 2016
tarafından
Sergey Fedoseev
Kaydeden (comit)
Tim Graham
Ara 15, 2016
Dosyalara gözat
Seçenekler
Dosyalara Gözat
İndir
Eposta Yamaları
Sade Fark
Fixed #25938 -- Factored out CPointerBase base class for GEOSBase/GDALBase.
üst
48844724
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
131 additions
and
194 deletions
+131
-194
base.py
django/contrib/gis/gdal/base.py
+3
-35
datasource.py
django/contrib/gis/gdal/datasource.py
+1
-7
driver.py
django/contrib/gis/gdal/driver.py
+1
-1
feature.py
django/contrib/gis/gdal/feature.py
+1
-7
geometries.py
django/contrib/gis/gdal/geometries.py
+1
-7
source.py
django/contrib/gis/gdal/raster/source.py
+2
-6
srs.py
django/contrib/gis/gdal/srs.py
+2
-14
base.py
django/contrib/gis/geos/base.py
+3
-35
geometry.py
django/contrib/gis/geos/geometry.py
+1
-10
prepared.py
django/contrib/gis/geos/prepared.py
+1
-6
io.py
django/contrib/gis/geos/prototypes/io.py
+6
-13
threadsafe.py
django/contrib/gis/geos/prototypes/threadsafe.py
+5
-5
ptr.py
django/contrib/gis/ptr.py
+38
-0
test_geos.py
tests/gis_tests/geos_tests/test_geos.py
+0
-47
test_io.py
tests/gis_tests/geos_tests/test_io.py
+1
-1
test_ptr.py
tests/gis_tests/test_ptr.py
+65
-0
No files found.
django/contrib/gis/gdal/base.py
Dosyayı görüntüle @
b01ceae8
from
ctypes
import
c_void_p
from
django.contrib.gis.gdal.error
import
GDALException
from
django.utils
import
six
class
GDALBase
(
object
):
"""
Base object for GDAL objects that has a pointer access property
that controls access to the underlying C pointer.
"""
# Initially the pointer is NULL.
_ptr
=
None
# Default allowed pointer type.
ptr_type
=
c_void_p
# Pointer access property.
def
_get_ptr
(
self
):
# Raise an exception if the pointer isn't valid don't
# want to be passing NULL pointers to routines --
# that's very bad.
if
self
.
_ptr
:
return
self
.
_ptr
else
:
raise
GDALException
(
'GDAL
%
s pointer no longer valid.'
%
self
.
__class__
.
__name__
)
from
django.contrib.gis.ptr
import
CPointerBase
def
_set_ptr
(
self
,
ptr
):
# Only allow the pointer to be set with pointers of the
# compatible type or None (NULL).
if
isinstance
(
ptr
,
six
.
integer_types
):
self
.
_ptr
=
self
.
ptr_type
(
ptr
)
elif
ptr
is
None
or
isinstance
(
ptr
,
self
.
ptr_type
):
self
.
_ptr
=
ptr
else
:
raise
TypeError
(
'Incompatible pointer type'
)
ptr
=
property
(
_get_ptr
,
_set_ptr
)
class
GDALBase
(
CPointerBase
):
null_ptr_exception_class
=
GDALException
django/contrib/gis/gdal/datasource.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -51,6 +51,7 @@ from django.utils.six.moves import range
# The OGR_DS_* routines are relevant here.
class
DataSource
(
GDALBase
):
"Wraps an OGR Data Source object."
destructor
=
capi
.
destroy_ds
def
__init__
(
self
,
ds_input
,
ds_driver
=
False
,
write
=
False
,
encoding
=
'utf-8'
):
# The write flag.
...
...
@@ -85,13 +86,6 @@ class DataSource(GDALBase):
# Raise an exception if the returned pointer is NULL
raise
GDALException
(
'Invalid data source file "
%
s"'
%
ds_input
)
def
__del__
(
self
):
"Destroys this DataStructure object."
try
:
capi
.
destroy_ds
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
__iter__
(
self
):
"Allows for iteration over the layers in a data source."
for
i
in
range
(
self
.
layer_count
):
...
...
django/contrib/gis/gdal/driver.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -49,7 +49,7 @@ class Driver(GDALBase):
# Attempting to get the GDAL/OGR driver by the string name.
for
iface
in
(
vcapi
,
rcapi
):
driver
=
iface
.
get_driver_by_name
(
force_bytes
(
name
))
driver
=
c_void_p
(
iface
.
get_driver_by_name
(
force_bytes
(
name
)
))
if
driver
:
break
elif
isinstance
(
dr_input
,
int
):
...
...
django/contrib/gis/gdal/feature.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -17,6 +17,7 @@ class Feature(GDALBase):
This class that wraps an OGR Feature, needs to be instantiated
from a Layer object.
"""
destructor
=
capi
.
destroy_feature
def
__init__
(
self
,
feat
,
layer
):
"""
...
...
@@ -27,13 +28,6 @@ class Feature(GDALBase):
self
.
ptr
=
feat
self
.
_layer
=
layer
def
__del__
(
self
):
"Releases a reference to this object."
try
:
capi
.
destroy_feature
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
__getitem__
(
self
,
index
):
"""
Gets the Field object at the specified index, which may be either
...
...
django/contrib/gis/gdal/geometries.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -62,6 +62,7 @@ from django.utils.six.moves import range
# The OGR_G_* routines are relevant here.
class
OGRGeometry
(
GDALBase
):
"Generally encapsulates an OGR geometry."
destructor
=
capi
.
destroy_geom
def
__init__
(
self
,
geom_input
,
srs
=
None
):
"Initializes Geometry on either WKT or an OGR pointer as input."
...
...
@@ -120,13 +121,6 @@ class OGRGeometry(GDALBase):
# Setting the class depending upon the OGR Geometry Type
self
.
__class__
=
GEO_CLASSES
[
self
.
geom_type
.
num
]
def
__del__
(
self
):
"Deletes this Geometry."
try
:
capi
.
destroy_geom
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
# Pickle routines
def
__getstate__
(
self
):
srs
=
self
.
srs
...
...
django/contrib/gis/gdal/raster/source.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -57,6 +57,8 @@ class GDALRaster(GDALBase):
"""
Wraps a raster GDAL Data Source object.
"""
destructor
=
capi
.
close_ds
def
__init__
(
self
,
ds_input
,
write
=
False
):
self
.
_write
=
1
if
write
else
0
Driver
.
ensure_registered
()
...
...
@@ -143,12 +145,6 @@ class GDALRaster(GDALBase):
else
:
raise
GDALException
(
'Invalid data source input type: "{}".'
.
format
(
type
(
ds_input
)))
def
__del__
(
self
):
try
:
capi
.
close_ds
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
__str__
(
self
):
return
self
.
name
...
...
django/contrib/gis/gdal/srs.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -41,6 +41,7 @@ class SpatialReference(GDALBase):
the SpatialReference object "provide[s] services to represent coordinate
systems (projections and datums) and to transform between them."
"""
destructor
=
capi
.
release_srs
def
__init__
(
self
,
srs_input
=
''
,
srs_type
=
'user'
):
"""
...
...
@@ -91,13 +92,6 @@ class SpatialReference(GDALBase):
elif
srs_type
==
'epsg'
:
self
.
import_epsg
(
srs_input
)
def
__del__
(
self
):
"Destroys this spatial reference."
try
:
capi
.
release_srs
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
__getitem__
(
self
,
target
):
"""
Returns the value of the given string attribute node, None if the node
...
...
@@ -329,6 +323,7 @@ class SpatialReference(GDALBase):
class
CoordTransform
(
GDALBase
):
"The coordinate system transformation object."
destructor
=
capi
.
destroy_ct
def
__init__
(
self
,
source
,
target
):
"Initializes on a source and target SpatialReference objects."
...
...
@@ -338,12 +333,5 @@ class CoordTransform(GDALBase):
self
.
_srs1_name
=
source
.
name
self
.
_srs2_name
=
target
.
name
def
__del__
(
self
):
"Deletes this Coordinate Transformation object."
try
:
capi
.
destroy_ct
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
def
__str__
(
self
):
return
'Transform from "
%
s" to "
%
s"'
%
(
self
.
_srs1_name
,
self
.
_srs2_name
)
django/contrib/gis/geos/base.py
Dosyayı görüntüle @
b01ceae8
from
ctypes
import
c_void_p
from
django.contrib.gis.geos.error
import
GEOSException
from
django.contrib.gis.ptr
import
CPointerBase
class
GEOSBase
(
object
):
"""
Base object for GEOS objects that has a pointer access property
that controls access to the underlying C pointer.
"""
# Initially the pointer is NULL.
_ptr
=
None
# Default allowed pointer type.
ptr_type
=
c_void_p
# Pointer access property.
def
_get_ptr
(
self
):
# Raise an exception if the pointer isn't valid don't
# want to be passing NULL pointers to routines --
# that's very bad.
if
self
.
_ptr
:
return
self
.
_ptr
else
:
raise
GEOSException
(
'NULL GEOS
%
s pointer encountered.'
%
self
.
__class__
.
__name__
)
def
_set_ptr
(
self
,
ptr
):
# Only allow the pointer to be set with pointers of the
# compatible type or None (NULL).
if
ptr
is
None
or
isinstance
(
ptr
,
self
.
ptr_type
):
self
.
_ptr
=
ptr
else
:
raise
TypeError
(
'Incompatible pointer type'
)
# Property for controlling access to the GEOS object pointers. Using
# this raises an exception when the pointer is NULL, thus preventing
# the C library from attempting to access an invalid memory location.
ptr
=
property
(
_get_ptr
,
_set_ptr
)
class
GEOSBase
(
CPointerBase
):
null_ptr_exception_class
=
GEOSException
django/contrib/gis/geos/geometry.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -33,6 +33,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
_GEOS_CLASSES
=
None
ptr_type
=
GEOM_PTR
destructor
=
capi
.
destroy_geom
has_cs
=
False
# Only Point, LineString, LinearRing have coordinate sequences
def
__init__
(
self
,
geo_input
,
srid
=
None
):
...
...
@@ -120,16 +121,6 @@ class GEOSGeometry(GEOSBase, ListMixin):
# geometries that do not have coordinate sequences)
self
.
_set_cs
()
def
__del__
(
self
):
"""
Destroys this Geometry; in other words, frees the memory used by the
GEOS C++ object.
"""
try
:
capi
.
destroy_geom
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
__copy__
(
self
):
"""
Returns a clone because the copy of a GEOSGeometry may contain an
...
...
django/contrib/gis/geos/prepared.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -9,6 +9,7 @@ class PreparedGeometry(GEOSBase):
operations.
"""
ptr_type
=
capi
.
PREPGEOM_PTR
destructor
=
capi
.
prepared_destroy
def
__init__
(
self
,
geom
):
# Keeping a reference to the original geometry object to prevent it
...
...
@@ -20,12 +21,6 @@ class PreparedGeometry(GEOSBase):
raise
TypeError
self
.
ptr
=
capi
.
geos_prepare
(
geom
.
ptr
)
def
__del__
(
self
):
try
:
capi
.
prepared_destroy
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
def
contains
(
self
,
other
):
return
capi
.
prepared_contains
(
self
.
ptr
,
other
.
ptr
)
...
...
django/contrib/gis/geos/prototypes/io.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -119,17 +119,10 @@ class IOBase(GEOSBase):
self
.
ptr
=
self
.
_constructor
()
# Loading the real destructor function at this point as doing it in
# __del__ is too late (import error).
self
.
_destructor
.
func
=
self
.
_
destructor
.
get_func
(
*
self
.
_destructor
.
args
,
**
self
.
_
destructor
.
kwargs
self
.
destructor
.
func
=
self
.
destructor
.
get_func
(
*
self
.
destructor
.
args
,
**
self
.
destructor
.
kwargs
)
def
__del__
(
self
):
# Cleaning up with the appropriate destructor.
try
:
self
.
_destructor
(
self
.
_ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
# ### Base WKB/WKT Reading and Writing objects ###
...
...
@@ -138,8 +131,8 @@ class IOBase(GEOSBase):
# objects.
class
_WKTReader
(
IOBase
):
_constructor
=
wkt_reader_create
_destructor
=
wkt_reader_destroy
ptr_type
=
WKT_READ_PTR
destructor
=
wkt_reader_destroy
def
read
(
self
,
wkt
):
if
not
isinstance
(
wkt
,
(
bytes
,
six
.
string_types
)):
...
...
@@ -149,8 +142,8 @@ class _WKTReader(IOBase):
class
_WKBReader
(
IOBase
):
_constructor
=
wkb_reader_create
_destructor
=
wkb_reader_destroy
ptr_type
=
WKB_READ_PTR
destructor
=
wkb_reader_destroy
def
read
(
self
,
wkb
):
"Returns a _pointer_ to C GEOS Geometry object from the given WKB."
...
...
@@ -166,8 +159,8 @@ class _WKBReader(IOBase):
# ### WKB/WKT Writer Classes ###
class
WKTWriter
(
IOBase
):
_constructor
=
wkt_writer_create
_destructor
=
wkt_writer_destroy
ptr_type
=
WKT_WRITE_PTR
destructor
=
wkt_writer_destroy
_trim
=
False
_precision
=
None
...
...
@@ -219,8 +212,8 @@ class WKTWriter(IOBase):
class
WKBWriter
(
IOBase
):
_constructor
=
wkb_writer_create
_destructor
=
wkb_writer_destroy
ptr_type
=
WKB_WRITE_PTR
destructor
=
wkb_writer_destroy
def
__init__
(
self
,
dim
=
2
):
super
(
WKBWriter
,
self
)
.
__init__
()
...
...
django/contrib/gis/geos/prototypes/threadsafe.py
Dosyayı görüntüle @
b01ceae8
import
threading
from
django.contrib.gis.geos.base
import
GEOSBase
from
django.contrib.gis.geos.libgeos
import
(
CONTEXT_PTR
,
error_h
,
lgeos
,
notice_h
,
)
class
GEOSContextHandle
(
object
):
class
GEOSContextHandle
(
GEOSBase
):
"""
Python object representing a GEOS context handle.
"""
ptr_type
=
CONTEXT_PTR
destructor
=
lgeos
.
finishGEOS_r
def
__init__
(
self
):
# Initializing the context handler for this thread with
# the notice and error handler.
self
.
ptr
=
lgeos
.
initGEOS_r
(
notice_h
,
error_h
)
def
__del__
(
self
):
if
self
.
ptr
and
lgeos
:
lgeos
.
finishGEOS_r
(
self
.
ptr
)
# Defining a thread-local object and creating an instance
# to hold a reference to GEOSContextHandle for this thread.
...
...
django/contrib/gis/ptr.py
0 → 100644
Dosyayı görüntüle @
b01ceae8
from
ctypes
import
c_void_p
class
CPointerBase
(
object
):
"""
Base class for objects that have a pointer access property
that controls access to the underlying C pointer.
"""
_ptr
=
None
# Initially the pointer is NULL.
ptr_type
=
c_void_p
destructor
=
None
null_ptr_exception_class
=
AttributeError
@property
def
ptr
(
self
):
# Raise an exception if the pointer isn't valid so that NULL pointers
# aren't passed to routines -- that's very bad.
if
self
.
_ptr
:
return
self
.
_ptr
raise
self
.
null_ptr_exception_class
(
'NULL
%
s pointer encountered.'
%
self
.
__class__
.
__name__
)
@ptr.setter
def
ptr
(
self
,
ptr
):
# Only allow the pointer to be set with pointers of the compatible
# type or None (NULL).
if
not
(
ptr
is
None
or
isinstance
(
ptr
,
self
.
ptr_type
)):
raise
TypeError
(
'Incompatible pointer type:
%
s.'
%
type
(
ptr
))
self
.
_ptr
=
ptr
def
__del__
(
self
):
"""
Free the memory used by the C++ object.
"""
if
self
.
destructor
and
self
.
_ptr
:
try
:
self
.
destructor
(
self
.
ptr
)
except
(
AttributeError
,
TypeError
):
pass
# Some part might already have been garbage collected
tests/gis_tests/geos_tests/test_geos.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -14,7 +14,6 @@ from django.contrib.gis.geos import (
LineString
,
MultiLineString
,
MultiPoint
,
MultiPolygon
,
Point
,
Polygon
,
fromfile
,
fromstr
,
)
from
django.contrib.gis.geos.base
import
GEOSBase
from
django.contrib.gis.geos.libgeos
import
geos_version_info
from
django.contrib.gis.shortcuts
import
numpy
from
django.template
import
Context
...
...
@@ -31,52 +30,6 @@ from ..test_data import TestDataMixin
@skipUnless
(
HAS_GEOS
,
"Geos is required."
)
class
GEOSTest
(
SimpleTestCase
,
TestDataMixin
):
def
test_base
(
self
):
"Tests out the GEOSBase class."
# Testing out GEOSBase class, which provides a `ptr` property
# that abstracts out access to underlying C pointers.
class
FakeGeom1
(
GEOSBase
):
pass
# This one only accepts pointers to floats
c_float_p
=
ctypes
.
POINTER
(
ctypes
.
c_float
)
class
FakeGeom2
(
GEOSBase
):
ptr_type
=
c_float_p
# Default ptr_type is `c_void_p`.
fg1
=
FakeGeom1
()
# Default ptr_type is C float pointer
fg2
=
FakeGeom2
()
# These assignments are OK -- None is allowed because
# it's equivalent to the NULL pointer.
fg1
.
ptr
=
ctypes
.
c_void_p
()
fg1
.
ptr
=
None
fg2
.
ptr
=
c_float_p
(
ctypes
.
c_float
(
5.23
))
fg2
.
ptr
=
None
# Because pointers have been set to NULL, an exception should be
# raised when we try to access it. Raising an exception is
# preferable to a segmentation fault that commonly occurs when
# a C method is given a NULL memory reference.
for
fg
in
(
fg1
,
fg2
):
# Equivalent to `fg.ptr`
with
self
.
assertRaises
(
GEOSException
):
fg
.
_get_ptr
()
# Anything that is either not None or the acceptable pointer type will
# result in a TypeError when trying to assign it to the `ptr` property.
# Thus, memory addresses (integers) and pointers of the incorrect type
# (in `bad_ptrs`) will not be allowed.
bad_ptrs
=
(
5
,
ctypes
.
c_char_p
(
b
'foobar'
))
for
bad_ptr
in
bad_ptrs
:
# Equivalent to `fg.ptr = bad_ptr`
with
self
.
assertRaises
(
TypeError
):
fg1
.
_set_ptr
(
bad_ptr
)
with
self
.
assertRaises
(
TypeError
):
fg2
.
_set_ptr
(
bad_ptr
)
def
test_wkt
(
self
):
"Testing WKT output."
for
g
in
self
.
geometries
.
wkt_out
:
...
...
tests/gis_tests/geos_tests/test_io.py
Dosyayı görüntüle @
b01ceae8
...
...
@@ -37,7 +37,7 @@ class GEOSIOTest(SimpleTestCase):
# Creating a WKTWriter instance, testing its ptr property.
wkt_w
=
WKTWriter
()
with
self
.
assertRaises
(
TypeError
):
wkt_w
.
_set_ptr
(
WKTReader
.
ptr_type
()
)
wkt_w
.
ptr
=
WKTReader
.
ptr_type
(
)
ref
=
GEOSGeometry
(
'POINT (5 23)'
)
ref_wkt
=
'POINT (5.0000000000000000 23.0000000000000000)'
...
...
tests/gis_tests/test_ptr.py
0 → 100644
Dosyayı görüntüle @
b01ceae8
import
ctypes
from
django.contrib.gis.ptr
import
CPointerBase
from
django.test
import
SimpleTestCase
,
mock
class
CPointerBaseTests
(
SimpleTestCase
):
def
test
(
self
):
destructor_mock
=
mock
.
Mock
()
class
NullPointerException
(
Exception
):
pass
class
FakeGeom1
(
CPointerBase
):
null_ptr_exception_class
=
NullPointerException
class
FakeGeom2
(
FakeGeom1
):
ptr_type
=
ctypes
.
POINTER
(
ctypes
.
c_float
)
destructor
=
destructor_mock
fg1
=
FakeGeom1
()
fg2
=
FakeGeom2
()
# These assignments are OK. None is allowed because it's equivalent
# to the NULL pointer.
fg1
.
ptr
=
fg1
.
ptr_type
()
fg1
.
ptr
=
None
fg2
.
ptr
=
fg2
.
ptr_type
(
ctypes
.
c_float
(
5.23
))
fg2
.
ptr
=
None
# Because pointers have been set to NULL, an exception is raised on
# access. Raising an exception is preferable to a segmentation fault
# that commonly occurs when a C method is given a NULL reference.
for
fg
in
(
fg1
,
fg2
):
with
self
.
assertRaises
(
NullPointerException
):
fg
.
ptr
# Anything that's either not None or the acceptable pointer type
# results in a TypeError when trying to assign it to the `ptr` property.
# Thus, memory addresses (integers) and pointers of the incorrect type
# (in `bad_ptrs`) aren't allowed.
bad_ptrs
=
(
5
,
ctypes
.
c_char_p
(
b
'foobar'
))
for
bad_ptr
in
bad_ptrs
:
for
fg
in
(
fg1
,
fg2
):
with
self
.
assertRaisesMessage
(
TypeError
,
'Incompatible pointer type'
):
fg
.
ptr
=
bad_ptr
# Object can be deleted without a destructor set.
fg
=
FakeGeom1
()
fg
.
ptr
=
fg
.
ptr_type
(
1
)
del
fg
# A NULL pointer isn't passed to the destructor.
fg
=
FakeGeom2
()
fg
.
ptr
=
None
del
fg
self
.
assertFalse
(
destructor_mock
.
called
)
# The destructor is called if set.
fg
=
FakeGeom2
()
ptr
=
fg
.
ptr_type
(
ctypes
.
c_float
(
1.
))
fg
.
ptr
=
ptr
del
fg
destructor_mock
.
assert_called_with
(
ptr
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment