@@ -1270,6 +1270,150 @@ def test_invalid_other_comp(self, data, comparison_op):
1270
1270
comparison_op (data , object ())
1271
1271
1272
1272
1273
+ class TestLogicalOps :
1274
+ """Various Series and DataFrame logical ops methods."""
1275
+
1276
+ def test_kleene_or (self ):
1277
+ a = pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" )
1278
+ b = pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1279
+ result = a | b
1280
+ expected = pd .Series (
1281
+ [True , True , True , True , False , None , True , None , None ],
1282
+ dtype = "boolean[pyarrow]" ,
1283
+ )
1284
+ tm .assert_series_equal (result , expected )
1285
+
1286
+ result = b | a
1287
+ tm .assert_series_equal (result , expected )
1288
+
1289
+ # ensure we haven't mutated anything inplace
1290
+ tm .assert_series_equal (
1291
+ a ,
1292
+ pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" ),
1293
+ )
1294
+ tm .assert_series_equal (
1295
+ b , pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1296
+ )
1297
+
1298
+ @pytest .mark .parametrize (
1299
+ "other, expected" ,
1300
+ [
1301
+ (None , [True , None , None ]),
1302
+ (pd .NA , [True , None , None ]),
1303
+ (True , [True , True , True ]),
1304
+ (np .bool_ (True ), [True , True , True ]),
1305
+ (False , [True , False , None ]),
1306
+ (np .bool_ (False ), [True , False , None ]),
1307
+ ],
1308
+ )
1309
+ def test_kleene_or_scalar (self , other , expected ):
1310
+ a = pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1311
+ result = a | other
1312
+ expected = pd .Series (expected , dtype = "boolean[pyarrow]" )
1313
+ tm .assert_series_equal (result , expected )
1314
+
1315
+ result = other | a
1316
+ tm .assert_series_equal (result , expected )
1317
+
1318
+ # ensure we haven't mutated anything inplace
1319
+ tm .assert_series_equal (
1320
+ a , pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1321
+ )
1322
+
1323
+ def test_kleene_and (self ):
1324
+ a = pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" )
1325
+ b = pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1326
+ result = a & b
1327
+ expected = pd .Series (
1328
+ [True , False , None , False , False , False , None , False , None ],
1329
+ dtype = "boolean[pyarrow]" ,
1330
+ )
1331
+ tm .assert_series_equal (result , expected )
1332
+
1333
+ result = b & a
1334
+ tm .assert_series_equal (result , expected )
1335
+
1336
+ # ensure we haven't mutated anything inplace
1337
+ tm .assert_series_equal (
1338
+ a ,
1339
+ pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" ),
1340
+ )
1341
+ tm .assert_series_equal (
1342
+ b , pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1343
+ )
1344
+
1345
+ @pytest .mark .parametrize (
1346
+ "other, expected" ,
1347
+ [
1348
+ (None , [None , False , None ]),
1349
+ (pd .NA , [None , False , None ]),
1350
+ (True , [True , False , None ]),
1351
+ (False , [False , False , False ]),
1352
+ (np .bool_ (True ), [True , False , None ]),
1353
+ (np .bool_ (False ), [False , False , False ]),
1354
+ ],
1355
+ )
1356
+ def test_kleene_and_scalar (self , other , expected ):
1357
+ a = pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1358
+ result = a & other
1359
+ expected = pd .Series (expected , dtype = "boolean[pyarrow]" )
1360
+ tm .assert_series_equal (result , expected )
1361
+
1362
+ result = other & a
1363
+ tm .assert_series_equal (result , expected )
1364
+
1365
+ # ensure we haven't mutated anything inplace
1366
+ tm .assert_series_equal (
1367
+ a , pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1368
+ )
1369
+
1370
+ def test_kleene_xor (self ):
1371
+ a = pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" )
1372
+ b = pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1373
+ result = a ^ b
1374
+ expected = pd .Series (
1375
+ [False , True , None , True , False , None , None , None , None ],
1376
+ dtype = "boolean[pyarrow]" ,
1377
+ )
1378
+ tm .assert_series_equal (result , expected )
1379
+
1380
+ result = b ^ a
1381
+ tm .assert_series_equal (result , expected )
1382
+
1383
+ # ensure we haven't mutated anything inplace
1384
+ tm .assert_series_equal (
1385
+ a ,
1386
+ pd .Series ([True ] * 3 + [False ] * 3 + [None ] * 3 , dtype = "boolean[pyarrow]" ),
1387
+ )
1388
+ tm .assert_series_equal (
1389
+ b , pd .Series ([True , False , None ] * 3 , dtype = "boolean[pyarrow]" )
1390
+ )
1391
+
1392
+ @pytest .mark .parametrize (
1393
+ "other, expected" ,
1394
+ [
1395
+ (None , [None , None , None ]),
1396
+ (pd .NA , [None , None , None ]),
1397
+ (True , [False , True , None ]),
1398
+ (np .bool_ (True ), [False , True , None ]),
1399
+ (np .bool_ (False ), [True , False , None ]),
1400
+ ],
1401
+ )
1402
+ def test_kleene_xor_scalar (self , other , expected ):
1403
+ a = pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1404
+ result = a ^ other
1405
+ expected = pd .Series (expected , dtype = "boolean[pyarrow]" )
1406
+ tm .assert_series_equal (result , expected )
1407
+
1408
+ result = other ^ a
1409
+ tm .assert_series_equal (result , expected )
1410
+
1411
+ # ensure we haven't mutated anything inplace
1412
+ tm .assert_series_equal (
1413
+ a , pd .Series ([True , False , None ], dtype = "boolean[pyarrow]" )
1414
+ )
1415
+
1416
+
1273
1417
def test_arrowdtype_construct_from_string_type_with_unsupported_parameters ():
1274
1418
with pytest .raises (NotImplementedError , match = "Passing pyarrow type" ):
1275
1419
ArrowDtype .construct_from_string ("not_a_real_dype[s, tz=UTC][pyarrow]" )
0 commit comments