@@ -796,14 +796,20 @@ def __setitem__(self, key, item):
796796 super ().__setitem__ (key , item )
797797
798798 @classmethod
799- def from_dict (cls , as_dict ):
799+ def from_dict (cls ,
800+ as_dict : dict ,
801+ allow_snake_case : bool = True ):
800802 """Construct an instance of the class from a :class:`dict <python:dict>` object.
801803
802804 :param as_dict: A :class:`dict <python:dict>` representation of the object.
803805 :type as_dict: :class:`dict <python:dict>`
804806
807+ :param allow_snake_case: If ``True``, interprets ``snake_case`` keys as equivalent
808+ to ``camelCase`` keys. Defaults to ``True``.
809+ :type allow_snake_case: :class:`bool <python:bool>`
810+
805811 :returns: A Python object representation of ``as_dict``.
806- :rtype: :class:`JavaScriptDict `
812+ :rtype: :class:`HighchartsMeta `
807813 """
808814 as_dict = validators .dict (as_dict , allow_empty = True )
809815 if not as_dict :
@@ -1120,9 +1126,98 @@ def _validate_js_literal(cls,
11201126 range = range ,
11211127 _break_loop_on_failure = True )
11221128 else :
1123- raise errors .HighchartsParseError ('._validate_js_function () expects '
1129+ raise errors .HighchartsParseError ('._validate_js_literal () expects '
11241130 'a str containing a valid '
1125- 'JavaScript function. Could not '
1126- 'find a valid function.' )
1131+ 'JavaScript literal object. Could '
1132+ 'not find a valid JS literal '
1133+ 'object.' )
11271134
11281135 return parsed , as_str
1136+
1137+ @classmethod
1138+ def from_js_literal (cls ,
1139+ as_str_or_file ,
1140+ allow_snake_case : bool = True ,
1141+ _break_loop_on_failure : bool = False ):
1142+ """Return a Python object representation of a Highcharts JavaScript object
1143+ literal.
1144+
1145+ :param as_str_or_file: The JavaScript object literal, represented either as a
1146+ :class:`str <python:str>` or as a filename which contains the JS object literal.
1147+ :type as_str_or_file: :class:`str <python:str>`
1148+
1149+ :param allow_snake_case: If ``True``, interprets ``snake_case`` keys as equivalent
1150+ to ``camelCase`` keys. Defaults to ``True``.
1151+ :type allow_snake_case: :class:`bool <python:bool>`
1152+
1153+ :param _break_loop_on_failure: If ``True``, will break any looping operations in
1154+ the event of a failure. Otherwise, will attempt to repair the failure. Defaults
1155+ to ``False``.
1156+ :type _break_loop_on_failure: :class:`bool <python:bool>`
1157+
1158+ :returns: A Python object representation of the Highcharts JavaScript object
1159+ literal.
1160+ :rtype: :class:`HighchartsMeta`
1161+ """
1162+ is_file = checkers .is_file (as_str_or_file )
1163+ if is_file :
1164+ with open (as_str_or_file , 'r' ) as file_ :
1165+ as_str = file_ .read ()
1166+ else :
1167+ as_str = as_str_or_file
1168+
1169+ parsed , updated_str = cls ._validate_js_literal (as_str )
1170+
1171+ as_dict = {}
1172+ if not parsed .body :
1173+ return cls ()
1174+
1175+ if len (parsed .body ) > 1 :
1176+ raise errors .HighchartsCollectionError (f'each JavaScript object literal is '
1177+ f'expected to contain one object. '
1178+ f'However, you attempted to parse '
1179+ f'{ len (parsed .body )} objects.' )
1180+
1181+ body = parsed .body [0 ]
1182+ if not checkers .is_type (body , 'VariableDeclaration' ) and \
1183+ _break_loop_on_failure is False :
1184+ prefixed_str = f'var randomVariable = { as_str } '
1185+ return cls .from_js_literal (prefixed_str ,
1186+ _break_loop_on_failure = True )
1187+ elif not checkers .is_type (body , 'VariableDeclaration' ):
1188+ raise errors .HighchartsVariableDeclarationError ('To parse a JavaScriot '
1189+ 'object literal, it is '
1190+ 'expected to be either a '
1191+ 'variable declaration or a'
1192+ 'standalone block statement.'
1193+ 'Input received did not '
1194+ 'conform.' )
1195+ declarations = body .declarations
1196+ if not declarations :
1197+ return cls ()
1198+
1199+ if len (declarations ) > 1 :
1200+ raise errors .HighchartsCollectionError (f'each JavaScript object literal is '
1201+ f'expected to contain one object. '
1202+ f'However, you attempted to parse '
1203+ f'{ len (parsed .body )} objects.' )
1204+ object_expression = declarations [0 ].init
1205+ if not checkers .is_type (object_expression , 'ObjectExpression' ):
1206+ raise errors .HighchartsParseError (f'Highcharts expects an object literal to '
1207+ f'to be defined as a standard '
1208+ f'ObjectExpression. Received: '
1209+ f'{ type (object_expression )} ' )
1210+
1211+ properties = object_expression .properties
1212+ if not properties :
1213+ return cls ()
1214+
1215+ key_value_pairs = [(x [0 ], x [1 ]) for x in get_key_value_pairs (properties ,
1216+ updated_str )]
1217+
1218+ for pair in key_value_pairs :
1219+ as_dict [pair [0 ]] = pair [1 ]
1220+
1221+ return cls .from_dict (as_dict ,
1222+ allow_snake_case = allow_snake_case )
1223+
0 commit comments