@@ -700,25 +700,33 @@ def get_validated_options(options, warn=True):
700
700
Returns a copy of options with invalid entries removed.
701
701
702
702
:Parameters:
703
- - `opts`: A dict of MongoDB URI options.
703
+ - `opts`: A dict containing MongoDB URI options.
704
704
- `warn` (optional): If ``True`` then warnings will be logged and
705
705
invalid options will be ignored. Otherwise, invalid options will
706
706
cause errors.
707
707
"""
708
- validated_options = {}
708
+ if isinstance (options , _CaseInsensitiveDictionary ):
709
+ validated_options = _CaseInsensitiveDictionary ()
710
+ get_normed_key = lambda x : x
711
+ get_setter_key = lambda x : options .cased_key (x )
712
+ else :
713
+ validated_options = {}
714
+ get_normed_key = lambda x : x .lower ()
715
+ get_setter_key = lambda x : x
716
+
709
717
for opt , value in iteritems (options ):
710
- lower = opt . lower ( )
718
+ normed_key = get_normed_key ( opt )
711
719
try :
712
720
validator = URI_OPTIONS_VALIDATOR_MAP .get (
713
- lower , raise_config_error )
721
+ normed_key , raise_config_error )
714
722
value = validator (opt , value )
715
723
except (ValueError , TypeError , ConfigurationError ) as exc :
716
724
if warn :
717
725
warnings .warn (str (exc ))
718
726
else :
719
727
raise
720
728
else :
721
- validated_options [lower ] = value
729
+ validated_options [get_setter_key ( normed_key ) ] = value
722
730
return validated_options
723
731
724
732
@@ -814,3 +822,83 @@ def read_concern(self):
814
822
.. versionadded:: 3.2
815
823
"""
816
824
return self .__read_concern
825
+
826
+
827
+ class _CaseInsensitiveDictionary (abc .MutableMapping ):
828
+ def __init__ (self , * args , ** kwargs ):
829
+ self .__casedkeys = {}
830
+ self .__data = {}
831
+ self .update (dict (* args , ** kwargs ))
832
+
833
+ def __contains__ (self , key ):
834
+ return key .lower () in self .__data
835
+
836
+ def __len__ (self ):
837
+ return len (self .__data )
838
+
839
+ def __iter__ (self ):
840
+ return (key for key in self .__casedkeys )
841
+
842
+ def __repr__ (self ):
843
+ return str ({self .__casedkeys [k ]: self .__data [k ] for k in self })
844
+
845
+ def __setitem__ (self , key , value ):
846
+ lc_key = key .lower ()
847
+ self .__casedkeys [lc_key ] = key
848
+ self .__data [lc_key ] = value
849
+
850
+ def __getitem__ (self , key ):
851
+ return self .__data [key .lower ()]
852
+
853
+ def __delitem__ (self , key ):
854
+ lc_key = key .lower ()
855
+ del self .__casedkeys [lc_key ]
856
+ del self .__data [lc_key ]
857
+
858
+ def __eq__ (self , other ):
859
+ if not isinstance (other , abc .Mapping ):
860
+ return NotImplemented
861
+ if len (self ) != len (other ):
862
+ return False
863
+ for key in other :
864
+ if self [key ] != other [key ]:
865
+ return False
866
+
867
+ return True
868
+
869
+ def get (self , key , default = None ):
870
+ return self .__data .get (key .lower (), default )
871
+
872
+ def pop (self , key , * args , ** kwargs ):
873
+ lc_key = key .lower ()
874
+ self .__casedkeys .pop (lc_key , None )
875
+ return self .__data .pop (lc_key , * args , ** kwargs )
876
+
877
+ def popitem (self ):
878
+ lc_key , cased_key = self .__casedkeys .popitem ()
879
+ value = self .__data .pop (lc_key )
880
+ return cased_key , value
881
+
882
+ def clear (self ):
883
+ self .__casedkeys .clear ()
884
+ self .__data .clear ()
885
+
886
+ def setdefault (self , key , default = None ):
887
+ lc_key = key .lower ()
888
+ if key in self :
889
+ return self .__data [lc_key ]
890
+ else :
891
+ self .__casedkeys [lc_key ] = key
892
+ self .__data [lc_key ] = default
893
+ return default
894
+
895
+ def update (self , other ):
896
+ if isinstance (other , _CaseInsensitiveDictionary ):
897
+ for key in other :
898
+ self [other .cased_key (key )] = other [key ]
899
+ else :
900
+ for key in other :
901
+ self [key ] = other [key ]
902
+
903
+ def cased_key (self , key ):
904
+ return self .__casedkeys [key .lower ()]
0 commit comments