11# cython: language=c++
2+ # cython: boundscheck=False
3+ # cython: wraparound=False
4+ # cython: cdivision=True
5+ # cython: overflowcheck=False
6+ # cython: initializedcheck=False
7+ # cython: nonecheck=False
8+ # cython: optimize.use_switch=True
9+ # cython: optimize.unpack_method_calls=True
10+ # cython: infer_types=True
211
312import json
413import logging
@@ -9,11 +18,14 @@ from flask import Response, g, request
918
1019from flask_inputfilter.exceptions import ValidationError
1120
21+ from flask_inputfilter.declarative.cimports cimport FieldDescriptor
1222from flask_inputfilter.mixins.cimports cimport DataMixin
1323from flask_inputfilter.models.cimports cimport BaseCondition, BaseFilter, BaseValidator, ExternalApiConfig, FieldModel
1424
1525from libcpp.vector cimport vector
1626from libcpp.string cimport string
27+ from libcpp cimport bool as cbool
28+ from libcpp.algorithm cimport find
1729
1830cdef dict _INTERNED_STRINGS = {
1931 " _condition" : sys.intern(" _condition" ),
@@ -45,7 +57,8 @@ cdef class InputFilter:
4557 """
4658
4759 def __cinit__ (self ) -> None:
48- self.methods = make_default_methods()
60+ cdef vector[string] default_methods = make_default_methods()
61+ self.methods = default_methods
4962 self.fields = {}
5063 self.conditions = []
5164 self.global_filters = []
@@ -57,8 +70,22 @@ cdef class InputFilter:
5770
5871 def __init__(self , methods: Optional[list[str]] = None ) -> None:
5972 if methods is not None:
60- self.methods.clear()
61- [self.methods.push_back(method.encode()) for method in methods]
73+ self._set_methods(methods )
74+
75+ self._register_decorator_components()
76+
77+ cdef void _set_methods(self , list methods ):
78+ """ Efficiently set HTTP methods using C++ vector operations."""
79+ cdef str method
80+ cdef bytes encoded_method
81+ cdef Py_ssize_t n = len (methods)
82+
83+ self .methods.clear()
84+ self .methods.reserve(n)
85+
86+ for method in methods:
87+ encoded_method = method.encode(' utf-8' )
88+ self .methods.push_back(string(encoded_method))
6289
6390 cpdef bint is_valid(self ):
6491 """
@@ -122,8 +149,14 @@ cdef class InputFilter:
122149 """
123150
124151 cdef InputFilter input_filter = cls ()
125- cdef string request_method = request.method.encode()
126- if not any (request_method == method for method in input_filter.methods):
152+ cdef bytes request_method_bytes = request.method.encode(' utf-8' )
153+ cdef string request_method = string(request_method_bytes)
154+ cdef vector[string].iterator method_it = find(
155+ input_filter.methods.begin(),
156+ input_filter.methods.end(),
157+ request_method
158+ )
159+ if method_it == input_filter.methods.end():
127160 return Response(status = 405 , response = " Method Not Allowed" )
128161
129162 if request.is_json:
@@ -206,6 +239,48 @@ cdef class InputFilter:
206239 """
207240 self .conditions.append(condition)
208241
242+ cdef void _register_decorator_components(self ):
243+ """ Register decorator-based components from the current class only."""
244+ cdef object cls , attr_value, conditions, validators, filters
245+ cdef str attr_name
246+ cdef list dir_attrs
247+ cdef FieldDescriptor field_desc
248+
249+ cls = self .__class__
250+ dir_attrs = dir (cls )
251+
252+ for attr_name in dir_attrs:
253+ if (< bytes> attr_name.encode(' utf-8' )).startswith(b" _" ):
254+ continue
255+
256+ attr_value = getattr (cls , attr_name, None )
257+ if attr_value is not None and isinstance (attr_value, FieldDescriptor):
258+ field_desc = < FieldDescriptor> attr_value
259+ self .fields[attr_name] = FieldModel(
260+ field_desc.required,
261+ field_desc._default,
262+ field_desc.fallback,
263+ field_desc.filters,
264+ field_desc.validators,
265+ field_desc.steps,
266+ field_desc.external_api,
267+ field_desc.copy,
268+ )
269+
270+ conditions = getattr (cls , " _conditions" , None )
271+ if conditions is not None :
272+ self .conditions.extend(conditions)
273+
274+ validators = getattr (cls , " _global_validators" , None )
275+ if validators is not None :
276+ self .global_validators.extend(validators)
277+
278+ filters = getattr (cls , " _global_filters" , None )
279+ if filters is not None :
280+ self .global_filters.extend(filters)
281+
282+ self .model_class = getattr (cls , " _model" , self .model_class)
283+
209284 cpdef list get_conditions(self ):
210285 """
211286 Retrieve the list of all registered conditions.
@@ -307,14 +382,19 @@ cdef class InputFilter:
307382
308383 cdef:
309384 Py_ssize_t i, n = len (self .fields)
310- dict result = {}
385+ dict result
311386 list field_names = list (self .fields.keys())
312387 str field
388+ object field_value
389+
390+ # Pre-allocate dictionary size for better performance
391+ result = {}
313392
314393 for i in range (n):
315394 field = field_names[i]
316- if field in self .data:
317- result[field] = self .data[field]
395+ field_value = self .data.get(field)
396+ if field_value is not None :
397+ result[field] = field_value
318398 return result
319399
320400 cpdef dict [str , Any] get_unfiltered_data(self ):
0 commit comments