/*[clinic input]
module _pickle
-class _pickle.Pickler
-class _pickle.PicklerMemoProxy
-class _pickle.Unpickler
-class _pickle.UnpicklerMemoProxy
+class _pickle.Pickler "PicklerObject *" "&Pickler_Type"
+class _pickle.PicklerMemoProxy "PicklerMemoProxyObject *" "&PicklerMemoProxyType"
+class _pickle.Unpickler "UnpicklerObject *" "&Unpickler_Type"
+class _pickle.UnpicklerMemoProxy "UnpicklerMemoProxyObject *" "&UnpicklerMemoProxyType"
[clinic start generated code]*/
/*[clinic end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
-/*[python input]
-class PicklerObject_converter(self_converter):
- type = "PicklerObject *"
-
-class PicklerMemoProxyObject_converter(self_converter):
- type = "PicklerMemoProxyObject *"
-
-class UnpicklerObject_converter(self_converter):
- type = "UnpicklerObject *"
-
-class UnpicklerMemoProxyObject_converter(self_converter):
- type = "UnpicklerMemoProxyObject *"
-[python start generated code]*/
-/*[python end generated code: checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709]*/
-
/* Bump this when new opcodes are added to the pickle protocol. */
enum {
HIGHEST_PROTOCOL = 4,
_pickle.Pickler.clear_memo
- self: PicklerObject
-
Clears the pickler's "memo".
The memo is the data structure that remembers which objects the
_pickle.Pickler.dump
- self: PicklerObject
obj: object
/
_pickle.Pickler.__init__
- self: PicklerObject
file: object
protocol: object = NULL
fix_imports: bool = True
/*[clinic input]
_pickle.PicklerMemoProxy.clear
- self: PicklerMemoProxyObject
-
Remove all items from memo.
[clinic start generated code]*/
/*[clinic input]
_pickle.PicklerMemoProxy.copy
- self: PicklerMemoProxyObject
-
Copy the memo to a new object.
[clinic start generated code]*/
/*[clinic input]
_pickle.PicklerMemoProxy.__reduce__
- self: PicklerMemoProxyObject
-
Implement pickle support.
[clinic start generated code]*/
{"load", (PyCFunction)_pickle_Unpickler_load, METH_NOARGS, _pickle_Unpickler_load__doc__},
static PyObject *
-_pickle_Unpickler_load_impl(PyObject *self);
+_pickle_Unpickler_load_impl(UnpicklerObject *self);
static PyObject *
-_pickle_Unpickler_load(PyObject *self, PyObject *Py_UNUSED(ignored))
+_pickle_Unpickler_load(UnpicklerObject *self, PyObject *Py_UNUSED(ignored))
{
return _pickle_Unpickler_load_impl(self);
}
static PyObject *
-_pickle_Unpickler_load_impl(PyObject *self)
-/*[clinic end generated code: checksum=fb1119422c5e03045d690d1cd6c457f1ca4c585d]*/
+_pickle_Unpickler_load_impl(UnpicklerObject *self)
+/*[clinic end generated code: checksum=5ccece694e9898856d916e0a87f0133d4537ebb9]*/
{
UnpicklerObject *unpickler = (UnpicklerObject*)self;
_pickle.Unpickler.find_class
- self: UnpicklerObject
module_name: object
global_name: object
/
_pickle.Unpickler.__init__
- self: UnpicklerObject
file: object
*
fix_imports: bool = True
/*[clinic input]
_pickle.UnpicklerMemoProxy.clear
- self: UnpicklerMemoProxyObject
-
Remove all items from memo.
[clinic start generated code]*/
/*[clinic input]
_pickle.UnpicklerMemoProxy.copy
- self: UnpicklerMemoProxyObject
-
Copy the memo to a new object.
[clinic start generated code]*/
/*[clinic input]
_pickle.UnpicklerMemoProxy.__reduce__
- self: UnpicklerMemoProxyObject
-
Implement pickling support.
[clinic start generated code]*/
# Should be full lines with \n eol characters.
self.initializers = []
+ # The C statements needed to dynamically modify the values
+ # parsed by the parse call, before calling the impl.
+ self.modifications = []
+
# The entries for the "keywords" array for PyArg_ParseTuple.
# Should be individual strings representing the names.
self.keywords = []
parser_definition_impl_call
+ {modifications}
{return_value} = {c_basename}_impl({impl_arguments});
__________________________________________________
parser_definition_no_positional
- if (!_PyArg_NoPositional("{name}", args))
+ if ({self_type_check}!_PyArg_NoPositional("{name}", args))
goto exit;
__________________________________________________
parser_definition_no_keywords
- if (!_PyArg_NoKeywords("{name}", kwargs))
+ if ({self_type_check}!_PyArg_NoKeywords("{name}", kwargs))
goto exit;
__________________________________________________
impl_definition = templates['impl_definition']
impl_prototype = parser_prototype = parser_definition = None
- parser_body_fields = None
+ parser_body_fields = ()
def parser_body(prototype, *fields):
nonlocal parser_body_fields
add, output = text_accumulator()
template_dict['docstring'] = self.docstring_for_c_string(f)
+ template_dict['self_name'] = template_dict['self_type'] = template_dict['self_type_check'] = ''
f_self.converter.set_template_dict(template_dict)
f.return_converter.render(f, data)
template_dict['declarations'] = "\n".join(data.declarations)
template_dict['initializers'] = "\n\n".join(data.initializers)
+ template_dict['modifications'] = '\n\n'.join(data.modifications)
template_dict['keywords'] = '"' + '", "'.join(data.keywords) + '"'
template_dict['format_units'] = ''.join(data.format_units)
template_dict['parse_arguments'] = ', '.join(data.parse_arguments)
declarations=template_dict['declarations'],
return_conversion=template_dict['return_conversion'],
initializers=template_dict['initializers'],
+ modifications=template_dict['modifications'],
cleanup=template_dict['cleanup'],
)
fail("Too many arguments for destination " + name + " new " + type)
if type =='file':
d = {}
- d['filename'] = filename = clinic.filename
- d['basename'], d['extension'] = os.path.splitext(filename)
+ filename = clinic.filename
+ d['path'] = filename
+ dirname, basename = os.path.split(filename)
+ if not dirname:
+ dirname = '.'
+ d['dirname'] = dirname
+ d['basename'] = basename
+ d['basename_root'], d['basename_extension'] = os.path.splitext(filename)
self.filename = args[0].format_map(d)
if type == 'two-pass':
self.id = None
self.add_destination("buffer", "buffer")
self.add_destination("two-pass", "two-pass")
if filename:
- self.add_destination("file", "file", "{basename}.clinic{extension}")
+ self.add_destination("file", "file", "{dirname}/clinic/{basename}.h")
d = self.destinations.get
self.field_destinations = collections.OrderedDict((
if destination.type == 'file':
try:
+ dirname = os.path.dirname(destination.filename)
+ try:
+ os.makedirs(dirname)
+ except FileExistsError:
+ if not os.path.isdir(dirname):
+ fail("Can't write to destination {}, "
+ "can't make directory {}!".format(
+ destination.filename, dirname))
with open(destination.filename, "rt") as f:
parser_2 = BlockParser(f.read(), language=self.language)
blocks = list(parser_2)
return "<clinic.Module " + repr(self.name) + " at " + str(id(self)) + ">"
class Class:
- def __init__(self, name, module=None, cls=None):
+ def __init__(self, name, module=None, cls=None, typedef=None, type_object=None):
self.name = name
self.module = module
self.cls = cls
+ self.typedef = typedef
+ self.type_object = type_object
self.parent = cls or module
self.classes = collections.OrderedDict()
# Should we show this parameter in the generated
# __text_signature__? This is *almost* always True.
+ # (It's only False for __new__, __init__, and METH_STATIC functions.)
show_in_signature = True
# Overrides the name used in a text signature.
if initializers:
data.initializers.append('/* initializers for ' + name + ' */\n' + initializers.rstrip())
+ # modifications
+ modifications = self.modify()
+ if modifications:
+ data.modifications.append('/* modifications for ' + name + ' */\n' + modifications.rstrip())
+
# keywords
data.keywords.append(original_name)
"""
return ""
+ def modify(self):
+ """
+ The C statements required to modify this variable after parsing.
+ Returns a string containing this code indented at column 0.
+ If no initialization is necessary, returns an empty string.
+ """
+ return ""
+
def cleanup(self):
"""
The C statements required to clean up after this variable.
return "PyTypeObject *", "type"
raise RuntimeError("Unhandled type of function f: " + repr(f.kind))
+def required_type_for_self_for_parser(f):
+ type, _ = correct_name_for_self(f)
+ if f.kind in (METHOD_INIT, METHOD_NEW, STATIC_METHOD, CLASS_METHOD):
+ return type
+ return None
+
class self_converter(CConverter):
"""
@property
def parser_type(self):
- kind = self.function.kind
- if kind == METHOD_NEW:
- return "PyTypeObject *"
- if kind == METHOD_INIT:
- return "PyObject *"
- return self.type
+ return required_type_for_self_for_parser(self.function) or self.type
def render(self, parameter, data):
"""
def set_template_dict(self, template_dict):
template_dict['self_name'] = self.name
template_dict['self_type'] = self.parser_type
+ template_dict['self_type_check'] = '({self_name} == {self_type_object}) &&\n '
self.keyword_only = False
self.group = 0
self.parameter_state = self.ps_start
+ self.seen_positional_with_default = False
self.indent = IndentStack()
self.kind = CALLABLE
self.coexist = False
module, cls = self.clinic._module_and_class(fields)
if cls:
fail("Can't nest a module inside a class!")
+
+ if name in module.classes:
+ fail("Already defined module " + repr(name) + "!")
+
m = Module(name, module)
module.modules[name] = m
self.block.signatures.append(m)
- def directive_class(self, name):
+ def directive_class(self, name, typedef, type_object):
fields = name.split('.')
in_classes = False
parent = self
so_far = []
module, cls = self.clinic._module_and_class(fields)
- c = Class(name, module, cls)
- if cls:
- cls.classes[name] = c
- else:
- module.classes[name] = c
+ parent = cls or module
+ if name in parent.classes:
+ fail("Already defined class " + repr(name) + "!")
+
+ c = Class(name, module, cls, typedef, type_object)
+ parent.classes[name] = c
self.block.signatures.append(c)
def directive_set(self, name, value):
else:
existing_function = None
if not existing_function:
+ print("class", cls, "module", module, "exsiting", existing)
+ print("cls. functions", cls.functions)
fail("Couldn't find existing function " + repr(existing) + "!")
fields = [x.strip() for x in full_name.split('.')]
self.block.signatures.append(self.function)
# insert a self converter automatically
- _, name = correct_name_for_self(self.function)
- sc = self.function.self_converter = self_converter(name, self.function)
+ type, name = correct_name_for_self(self.function)
+ kwargs = {}
+ if cls and type == "PyObject *":
+ kwargs['type'] = cls.typedef
+ sc = self.function.self_converter = self_converter(name, self.function, **kwargs)
p_self = Parameter(sc.name, inspect.Parameter.POSITIONAL_ONLY, function=self.function, converter=sc)
self.function.parameters[sc.name] = p_self
# "parameter_state". (Previously the code was a miasma of ifs and
# separate boolean state variables.) The states are:
#
- # [ [ a, b, ] c, ] d, e, f, [ g, h, [ i ] ] / <- line
- # 01 2 3 4 5 6 <- state transitions
+ # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] / <- line
+ # 01 2 3 4 5 6 7 <- state transitions
#
# 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
# 1: ps_left_square_before. left square brackets before required parameters.
# 2: ps_group_before. in a group, before required parameters.
- # 3: ps_required. required parameters. (renumber left groups!)
- # 4: ps_group_after. in a group, after required parameters.
- # 5: ps_right_square_after. right square brackets after required parameters.
- # 6: ps_seen_slash. seen slash.
+ # 3: ps_required. required parameters, positional-or-keyword or positional-only
+ # (we don't know yet). (renumber left groups!)
+ # 4: ps_optional. positional-or-keyword or positional-only parameters that
+ # now must have default values.
+ # 5: ps_group_after. in a group, after required parameters.
+ # 6: ps_right_square_after. right square brackets after required parameters.
+ # 7: ps_seen_slash. seen slash.
ps_start, ps_left_square_before, ps_group_before, ps_required, \
- ps_group_after, ps_right_square_after, ps_seen_slash = range(7)
+ ps_optional, ps_group_after, ps_right_square_after, ps_seen_slash = range(8)
def state_parameters_start(self, line):
if self.ignore_line(line):
elif self.parameter_state == self.ps_group_before:
if not self.group:
self.to_required()
- elif self.parameter_state == self.ps_group_after:
+ elif self.parameter_state in (self.ps_group_after, self.ps_optional):
pass
else:
- fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
+ fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".a)")
base, equals, default = line.rpartition('=')
if not equals:
base = default
default = None
+
module = None
try:
ast_input = "def x({}): pass".format(base)
module = ast.parse(ast_input)
except SyntaxError:
try:
+ # the last = was probably inside a function call, like
+ # i: int(nullable=True)
+ # so assume there was no actual default value.
default = None
ast_input = "def x({}): pass".format(line)
module = ast.parse(ast_input)
name, legacy, kwargs = self.parse_converter(parameter.annotation)
if not default:
+ if self.parameter_state == self.ps_optional:
+ fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter a parameter with a default!")
value = unspecified
if 'py_default' in kwargs:
fail("You can't specify py_default without specifying a default value!")
else:
+ if self.parameter_state == self.ps_required:
+ self.parameter_state = self.ps_optional
default = default.strip()
bad = False
ast_input = "x = {}".format(default)
+ bad = False
try:
module = ast.parse(ast_input)
elif self.parameter_state in (self.ps_required, self.ps_group_after):
self.parameter_state = self.ps_group_after
else:
- fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
+ fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".b)")
self.group += 1
elif symbol == ']':
if not self.group:
elif self.parameter_state in (self.ps_group_after, self.ps_right_square_after):
self.parameter_state = self.ps_right_square_after
else:
- fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
+ fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".c)")
elif symbol == '/':
- # ps_required is allowed here, that allows positional-only without option groups
+ # ps_required and ps_optional are allowed here, that allows positional-only without option groups
# to work (and have default values!)
- if (self.parameter_state not in (self.ps_required, self.ps_right_square_after, self.ps_group_before)) or self.group:
- fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ")")
+ if (self.parameter_state not in (self.ps_required, self.ps_optional, self.ps_right_square_after, self.ps_group_before)) or self.group:
+ fail("Function " + self.function.name + " has an unsupported group configuration. (Unexpected state " + str(self.parameter_state) + ".d)")
if self.keyword_only:
fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
self.parameter_state = self.ps_seen_slash