@@ -1305,13 +1305,18 @@ public static void InitializeForFinalization(CodeContext/*!*/ context, object ne
13051305 iwr . SetFinalizer ( new WeakRefTracker ( iwr , nif , nif ) ) ;
13061306 }
13071307
1308- internal static object ? CallPrepare ( CodeContext /*!*/ context , PythonType meta , string name , PythonTuple bases , PythonDictionary dict ) {
1308+ internal static object ? CallPrepare ( CodeContext /*!*/ context , PythonType meta , string name , PythonTuple bases , PythonDictionary ? keywords , PythonDictionary dict ) {
13091309 object ? classdict = dict ;
13101310
13111311 // if available, call the __prepare__ method to get the classdict (PEP 3115)
13121312 if ( meta . TryLookupSlot ( context , "__prepare__" , out PythonTypeSlot pts ) ) {
13131313 if ( pts . TryGetValue ( context , null , meta , out object value ) ) {
1314- classdict = PythonOps . CallWithContext ( context , value , name , bases ) ;
1314+ if ( keywords is null || keywords . Count == 0 ) {
1315+ classdict = PythonOps . CallWithContext ( context , value , name , bases ) ;
1316+ } else {
1317+ var args = new object [ ] { name , bases } ;
1318+ classdict = PythonCalls . CallWithKeywordArgs ( context , value , args , keywords ) ;
1319+ }
13151320 // copy the contents of dict to the classdict
13161321 foreach ( var pair in dict )
13171322 context . LanguageContext . SetIndex ( classdict , pair . Key , pair . Value ) ;
@@ -1321,10 +1326,15 @@ public static void InitializeForFinalization(CodeContext/*!*/ context, object ne
13211326 return classdict ;
13221327 }
13231328
1324- public static object MakeClass ( FunctionCode funcCode , Func < CodeContext , CodeContext > body , CodeContext /*!*/ parentContext , string name , PythonTuple bases , object metaclass , string selfNames ) {
1329+ public static object MakeClass ( FunctionCode funcCode , Func < CodeContext , CodeContext > body , CodeContext /*!*/ parentContext , string name , PythonTuple bases , PythonDictionary ? keywords , string selfNames ) {
13251330 Func < CodeContext , CodeContext > func = GetClassCode ( parentContext , funcCode , body ) ;
13261331
1327- return MakeClass ( parentContext , name , bases , metaclass , selfNames , func ( parentContext ) . Dict ) ;
1332+ object ? metaclass = null ;
1333+ if ( keywords is not null && keywords . TryGetValueNoMissing ( "metaclass" , out metaclass ) ) {
1334+ keywords . RemoveDirect ( "metaclass" ) ; // keyword argument consumed
1335+ }
1336+
1337+ return MakeClass ( parentContext , name , bases , metaclass , keywords , selfNames , func ( parentContext ) . Dict ) ;
13281338 }
13291339
13301340 private static Func < CodeContext , CodeContext > GetClassCode ( CodeContext /*!*/ context , FunctionCode funcCode , Func < CodeContext , CodeContext > body ) {
@@ -1342,7 +1352,9 @@ private static Func<CodeContext, CodeContext> GetClassCode(CodeContext/*!*/ cont
13421352 }
13431353 }
13441354
1345- private static object MakeClass ( CodeContext /*!*/ context , string name , PythonTuple bases , object metaclass , string selfNames , PythonDictionary vars ) {
1355+ private static object MakeClass ( CodeContext /*!*/ context , string name , PythonTuple bases , object ? metaclass , PythonDictionary ? keywords , string selfNames , PythonDictionary vars ) {
1356+ Debug . Assert ( metaclass is null || keywords is not null ) ;
1357+
13461358 foreach ( object ? dt in bases ) {
13471359 if ( dt is TypeGroup ) {
13481360 object ? [ ] newBases = new object [ bases . Count ] ;
@@ -1368,6 +1380,9 @@ private static object MakeClass(CodeContext/*!*/ context, string name, PythonTup
13681380 }
13691381
13701382 if ( metaclass is null ) {
1383+ if ( keywords != null && keywords . Count > 0 ) {
1384+ throw TypeError ( "type() takes no keyword arguments" ) ;
1385+ }
13711386 // this makes sure that object is a base
13721387 if ( bases . Count == 0 ) {
13731388 bases = PythonTuple . MakeTuple ( DynamicHelpers . GetPythonTypeFromType ( typeof ( object ) ) ) ;
@@ -1377,14 +1392,13 @@ private static object MakeClass(CodeContext/*!*/ context, string name, PythonTup
13771392
13781393 object ? classdict = vars ;
13791394
1380- if ( metaclass is PythonType ) {
1381- classdict = CallPrepare ( context , ( PythonType ) metaclass , name , bases , vars ) ;
1395+ if ( metaclass is PythonType metatype ) {
1396+ classdict = CallPrepare ( context , metatype , name , bases , keywords , vars ) ;
13821397 }
13831398
13841399 // eg:
1385- // def foo(*args): print args
1386- // __metaclass__ = foo
1387- // class bar: pass
1400+ // def foo(*args): print(args)
1401+ // class bar(metaclass=foo): pass
13881402 // calls our function...
13891403 PythonContext pc = context . LanguageContext ;
13901404
@@ -1394,7 +1408,8 @@ private static object MakeClass(CodeContext/*!*/ context, string name, PythonTup
13941408 metaclass ,
13951409 name ,
13961410 bases ,
1397- classdict
1411+ classdict ,
1412+ keywords
13981413 ) ;
13991414
14001415 if ( obj is PythonType newType && newType . BaseTypes . Count == 0 ) {
@@ -1506,12 +1521,21 @@ public static void DictMerge(CodeContext context, PythonDictionary dict, object?
15061521 // enumerate the keys getting their values
15071522 IEnumerator enumerator = GetEnumerator ( keys ) ;
15081523 while ( enumerator . MoveNext ( ) ) {
1509- object ? o = enumerator . Current ;
1510- if ( dict . ContainsKey ( o ) && ( o is string || o is Extensible < string > ) ) {
1511- throw TypeError ( $ "function got multiple values for keyword argument '{ o } '") ;
1512- }
1513- dict [ o ] = PythonOps . GetIndex ( context , item , o ) ;
1524+ object ? key = enumerator . Current ;
1525+ object ? value = PythonOps . GetIndex ( context , item , key ) ;
1526+ DictMergeOne ( context , dict , key , value ) ;
1527+ }
1528+ }
1529+
1530+ /// <summary>
1531+ /// Like DictMerge but for a single key/value element
1532+ /// </summary>
1533+ [ EditorBrowsable ( EditorBrowsableState . Never ) ]
1534+ public static void DictMergeOne ( CodeContext context , PythonDictionary dict , object ? key , object ? value ) {
1535+ if ( dict . ContainsKey ( key ) && ( key is string || key is Extensible < string > ) ) {
1536+ throw TypeError ( $ "function got multiple values for keyword argument '{ key } '") ;
15141537 }
1538+ dict [ key ] = value ;
15151539 }
15161540
15171541 /// <summary>
0 commit comments