1. Larry Hastings
  2. python-clinic

Commits

Larry Hastings  committed b0afcd6

Language is now an ABC.

  • Participants
  • Parent commits 11c12ce
  • Branches default

Comments (0)

Files changed (2)

File Modules/posixmodule.c

View file
 /*[python]
 
 @add_converter
-class path_t_converter(Converter):
+class path_t_converter(CConverter):
 
     type = "path_t"
     impl_by_reference = True
         return "path_cleanup(&" + self.name + ");"
 
 @add_converter
-class dir_fd_converter(Converter):
+class dir_fd_converter(CConverter):
     type = 'int'
     converter = 'OS_STAT_DIR_FD_CONVERTER'
 

File clinic.py

View file
+import abc
 import ast
 import atexit
 import clinic
 #
 # Look at merging add_converter + Converter into a metaclass to remove need for add_converter
 #
-# Make it more explicit that Converter is tied to C
-#
-# Make Language an ABC with render() an abstractmethod
-#
 # soon:
 #
 # * allow mixing any two of {positional-only, positional-or-keyword,
 #       * dict constructor uses positional-only and keyword-only
 #       * max and min use positional only with an optional group
 #         and keyword-only
+#
 # * Generate forward slash for docstring first line
 #   (if I get positional-only syntax pep accepted)
 #
         self.cleanup = []
 
 
-class Language:
+class Language(metaclass=abc.ABCMeta):
 
     start_line = ""
     body_prefix = ""
     stop_line = ""
     checksum_line = ""
 
-    def __init__(self):
+    @abc.abstractmethod
+    def render(self, block):
+        pass
+
+    def validate(self):
         def assert_only_one(field, token='dsl_name'):
-            line = getattr(self.language, field)
+            line = getattr(self, field)
             token = '{' + token + '}'
             if not len(line.split(token)) == 2:
                 fail(self.__class__.__name__ + " " + field + " must contain " + token + " exactly once!")
         assert_only_one('checksum_line')
         assert_only_one('checksum_line', 'checksum')
 
-        if len(self.language.body_prefix.split('{dsl_name}')) >= 3:
+        if len(self.body_prefix.split('{dsl_name}')) >= 3:
             fail(self.__class__.__name__ + " body_prefix may contain " + token + " once at most!")
 
-    def render(self, block):
-        fail("Pure virtual function " + self.__class__.__name__ + ".render called.")
 
 
 class PythonLanguage(Language):
 
         "language" should be a Language object.
         """
+        language.validate()
+
         self.input = collections.deque(reversed(input.splitlines(keepends=True)))
         self.block_start_line_number = self.line_number = 0
 
 # these callables must be of the form:
 #   def foo(name, default, *, ...)
 # The callable may have any number of keyword-only parameters.
-# The callable must return a Converter object.
+# The callable must return a CConverter object.
 # The callable should not call builtins.print.
 converters = {}
 
 # these callables must be of the form:
 #   def foo(*, ...)
 # The callable may have any number of keyword-only parameters.
-# The callable must return a Converter object.
+# The callable must return a CConverter object.
 # The callable should not call builtins.print.
 return_converters = {}
 
     return closure
 
 
-class Converter:
+class CConverter:
     """
     For the init function, self, name, function, and default
     must be keyword-or-positional parameters.  All other
 
 
 @add_converter
-class int_converter(Converter):
+class int_converter(CConverter):
     type = 'int'
     format_unit = 'i'
 
         self.c_default = str(int(self.default))
 
 @add_converter
-class long_converter(Converter):
+class long_converter(CConverter):
     type = 'long'
     format_unit = 'l'
 
 @add_converter
-class char_converter(Converter):
+class char_converter(CConverter):
     type = 'char'
     format_unit = 'c'
 
 @add_converter
-class object_converter(Converter):
+class object_converter(CConverter):
     type = 'PyObject *'
     format_unit = 'O'
 
             self.encoding = type
 
 @add_converter
-class str_converter(Converter):
+class str_converter(CConverter):
     type = 'const char *'
     format_unit = 's'
 
 @add_converter
-class unicode_converter(Converter):
+class unicode_converter(CConverter):
     type = 'PyObject *'
     format_unit = 'U'
 
 @add_converter
 @add_legacy_converter('s*', zeroes=True)
 @add_legacy_converter('z*', zeroes=True, nullable=True)
-class Py_buffer_converter(Converter):
+class Py_buffer_converter(CConverter):
     type = 'Py_buffer'
     format_unit = 'y*'
     impl_by_reference = True
     return f
 
 
-class ReturnConverter:
+class CReturnConverter:
 
     type = 'PyObject *'
     default = None
         """
         pass
 
-add_return_converter(ReturnConverter, 'object')
+add_return_converter(CReturnConverter, 'object')
 
 @add_return_converter
-class int_return_converter(ReturnConverter):
+class int_return_converter(CReturnConverter):
     type = 'int'
 
     def render(self, function, data):
             'return_value = PyLong_FromLong((long)_return_value);\n')
 
 @add_return_converter
-class long_return_converter(ReturnConverter):
+class long_return_converter(CReturnConverter):
     type = 'long'
 
     def render(self, function, data):
             'return_value = PyLong_FromLong(_return_value);\n')
 
 @add_return_converter
-class Py_ssize_t_return_converter(ReturnConverter):
+class Py_ssize_t_return_converter(CReturnConverter):
     type = 'Py_ssize_t'
 
     def render(self, function, data):
             'return_value = PyLong_FromSsize_t(_return_value);\n')
 
 @add_return_converter
-class DecodeFSDefault_return_converter(ReturnConverter):
+class DecodeFSDefault_return_converter(CReturnConverter):
     type = 'char *'
 
     def render(self, function, data):
         c_basename = c_basename.strip() or None
 
         if not returns:
-            return_converter = ReturnConverter()
+            return_converter = CReturnConverter()
         else:
             ast_input = "def x() -> {}: pass".format(returns)
             module = None