11
11
12
12
import copy
13
13
14
- from typing import Dict , Any , TYPE_CHECKING , Optional
15
-
16
14
del absolute_import , division , print_function
17
15
18
16
19
- def _process_metadata_dict (metadata , __dict__ ):
20
- # type: (Optional[Any], Optional[Dict[str, Any]]) -> Dict[str, Any]
21
- """
22
- Provide standardized handling for keywords related to metadata.
23
- """
24
- if __dict__ is None :
25
- __dict__ = {}
26
-
27
- if metadata is not None :
28
- if "metadata" in __dict__ :
29
- raise KeyError ("Cannot provide metadata by keyword and in __dict__" )
30
- __dict__ ["metadata" ] = metadata
31
-
32
- return __dict__
33
-
34
-
35
17
def _isstr (value ):
36
18
"""
37
19
Check to see if this is a stringlike or a (nested) iterable of stringlikes
@@ -48,60 +30,56 @@ def _isstr(value):
48
30
# Contains common methods and properties to all axes
49
31
@set_module ("boost_histogram.axis" )
50
32
class Axis (object ):
51
- __slots__ = ("_ax" ,)
33
+ __slots__ = ("_ax" , "__dict__" )
52
34
53
- # Workaround for bug https://github.com/python/mypy/issues/6523 in mypy
54
- if TYPE_CHECKING :
55
- __dict__ = Dict [ str , Any ]()
56
- else :
35
+ def __setattr__ ( self , attr , value ):
36
+ if attr == "__dict__" :
37
+ self . _ax . metadata = value
38
+ object . __setattr__ ( self , attr , value )
57
39
58
- @property
59
- def __dict__ (self ):
60
- # type: () -> Dict[str, Any]
61
- return self ._ax .metadata
40
+ def __getattr__ (self , attr ):
41
+ if attr == "metadata" :
42
+ return None
43
+ raise AttributeError (
44
+ "object {0} has not attribute {1}" .format (self .__class__ .__name__ , attr )
45
+ )
46
+
47
+ def __init__ (self , ax , metadata , __dict__ ):
48
+ """
49
+ ax: the C++ object
50
+ metadata: the metadata keyword contents
51
+ __dict__: the __dict__ keyword contents
52
+ """
62
53
63
- @__dict__ .deleter
64
- def __dict__ (self ):
65
- # type: (Dict[str, Any]) -> None
66
- self ._ax .metadata = {}
54
+ self ._ax = ax
55
+
56
+ if __dict__ is not None and metadata is not None :
57
+ raise KeyError (
58
+ "Cannot provide metadata by keyword and __dict__, use __dict__ only"
59
+ )
60
+ elif __dict__ is not None :
61
+ self .__dict__ = __dict__
62
+ elif metadata is not None :
63
+ self .__dict__ ["metadata" ] = metadata
64
+
65
+ self ._ax .metadata = self .__dict__
66
+ assert self .__dict__ is self ._ax .metadata
67
67
68
- # Required for Python 2 + __dict__
69
68
def __setstate__ (self , state ):
70
69
self ._ax = state ["_ax" ]
70
+ self .__dict__ = self ._ax .metadata
71
+ assert self .__dict__ is self ._ax .metadata
71
72
72
73
def __getstate__ (self ):
73
74
return {"_ax" : self ._ax }
74
75
75
- def __getattr__ (self , item ):
76
- if item == "_ax" :
77
- return Axis .__dict__ [item ].__get__ (self )
78
- elif item in self ._ax .metadata :
79
- return self ._ax .metadata [item ]
80
- elif item == "metadata" :
81
- return None
82
- else :
83
- msg = "'{}' object has no attribute '{}' in {}" .format (
84
- type (self ).__name__ , item , set (self ._ax .metadata )
85
- )
86
- raise AttributeError (msg )
87
-
88
- def __setattr__ (self , item , value ):
89
- if item == "_ax" :
90
- Axis .__dict__ [item ].__set__ (self , value )
91
- elif item == "__dict__" :
92
- self ._ax .metadata = value
93
- else :
94
- self ._ax .metadata [item ] = value
95
-
96
76
def __copy__ (self ):
97
77
other = self .__class__ .__new__ (self .__class__ )
98
78
other ._ax = copy .copy (self ._ax )
79
+ other .__dict__ = other ._ax .metadata
80
+ assert other .__dict__ is other ._ax .metadata
99
81
return other
100
82
101
- def __dir__ (self ):
102
- metadata = list (self ._ax .metadata )
103
- return sorted (dir (type (self )) + metadata )
104
-
105
83
def index (self , value ):
106
84
"""
107
85
Return the fractional index(es) given a value (or values) on the axis.
@@ -142,6 +120,8 @@ def __ne__(self, other):
142
120
def _convert_cpp (cls , cpp_object ):
143
121
nice_ax = cls .__new__ (cls )
144
122
nice_ax ._ax = cpp_object
123
+ nice_ax .__dict__ = cpp_object .metadata
124
+ assert nice_ax ._ax .metadata == nice_ax .__dict__
145
125
return nice_ax
146
126
147
127
def __len__ (self ):
@@ -304,9 +284,6 @@ def __init__(self, bins, start, stop, **kwargs):
304
284
The full metadata dictionary
305
285
"""
306
286
307
- # Inheriting an axis and forgetting to add __slots__ should be an error
308
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
309
-
310
287
with KWArgs (kwargs ) as k :
311
288
metadata = k .optional ("metadata" )
312
289
transform = k .optional ("transform" )
@@ -315,8 +292,6 @@ def __init__(self, bins, start, stop, **kwargs):
315
292
underflow = True , overflow = True , growth = False , circular = False
316
293
)
317
294
318
- __dict__ = _process_metadata_dict (metadata , __dict__ )
319
-
320
295
if transform is not None :
321
296
if options != {"underflow" , "overflow" }:
322
297
raise KeyError ("Transform supplied, cannot change other options" )
@@ -327,29 +302,29 @@ def __init__(self, bins, start, stop, **kwargs):
327
302
):
328
303
raise TypeError ("You must pass an instance, use {}()" .format (transform ))
329
304
330
- self . _ax = transform ._produce (bins , start , stop )
305
+ ax = transform ._produce (bins , start , stop )
331
306
332
307
elif options == {"growth" , "underflow" , "overflow" }:
333
- self . _ax = ca .regular_uoflow_growth (bins , start , stop )
308
+ ax = ca .regular_uoflow_growth (bins , start , stop )
334
309
elif options == {"underflow" , "overflow" }:
335
- self . _ax = ca .regular_uoflow (bins , start , stop )
310
+ ax = ca .regular_uoflow (bins , start , stop )
336
311
elif options == {"underflow" }:
337
- self . _ax = ca .regular_uflow (bins , start , stop )
312
+ ax = ca .regular_uflow (bins , start , stop )
338
313
elif options == {"overflow" }:
339
- self . _ax = ca .regular_oflow (bins , start , stop )
314
+ ax = ca .regular_oflow (bins , start , stop )
340
315
elif options == {"circular" , "underflow" , "overflow" } or options == {
341
316
"circular" ,
342
317
"overflow" ,
343
318
}:
344
319
# growth=True, underflow=False is also correct
345
- self . _ax = ca .regular_circular (bins , start , stop )
320
+ ax = ca .regular_circular (bins , start , stop )
346
321
347
322
elif options == set ():
348
- self . _ax = ca .regular_none (bins , start , stop )
323
+ ax = ca .regular_none (bins , start , stop )
349
324
else :
350
325
raise KeyError ("Unsupported collection of options" )
351
326
352
- self . _ax . metadata = __dict__
327
+ super ( Regular , self ). __init__ ( ax , metadata , __dict__ )
353
328
354
329
def _repr_args (self ):
355
330
"Return inner part of signature for use in repr"
@@ -415,38 +390,33 @@ def __init__(self, edges, **kwargs):
415
390
The full metadata dictionary
416
391
"""
417
392
418
- # Inheriting an axis and forgetting to add __slots__ should be an error
419
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
420
-
421
393
with KWArgs (kwargs ) as k :
422
394
metadata = k .optional ("metadata" )
423
395
__dict__ = k .optional ("__dict__" )
424
396
options = k .options (
425
397
underflow = True , overflow = True , circular = False , growth = False
426
398
)
427
399
428
- __dict__ = _process_metadata_dict (metadata , __dict__ )
429
-
430
400
if options == {"growth" , "underflow" , "overflow" }:
431
- self . _ax = ca .variable_uoflow_growth (edges )
401
+ ax = ca .variable_uoflow_growth (edges )
432
402
elif options == {"underflow" , "overflow" }:
433
- self . _ax = ca .variable_uoflow (edges )
403
+ ax = ca .variable_uoflow (edges )
434
404
elif options == {"underflow" }:
435
- self . _ax = ca .variable_uflow (edges )
405
+ ax = ca .variable_uflow (edges )
436
406
elif options == {"overflow" }:
437
- self . _ax = ca .variable_oflow (edges )
407
+ ax = ca .variable_oflow (edges )
438
408
elif options == {"circular" , "underflow" , "overflow" ,} or options == {
439
409
"circular" ,
440
410
"overflow" ,
441
411
}:
442
412
# growth=True, underflow=False is also correct
443
- self . _ax = ca .variable_circular (edges )
413
+ ax = ca .variable_circular (edges )
444
414
elif options == set ():
445
- self . _ax = ca .variable_none (edges )
415
+ ax = ca .variable_none (edges )
446
416
else :
447
417
raise KeyError ("Unsupported collection of options" )
448
418
449
- self . _ax . metadata = __dict__
419
+ super ( Variable , self ). __init__ ( ax , metadata , __dict__ )
450
420
451
421
def _repr_args (self ):
452
422
"Return inner part of signature for use in repr"
@@ -500,36 +470,31 @@ def __init__(self, start, stop, **kwargs):
500
470
The full metadata dictionary
501
471
"""
502
472
503
- # Inheriting an axis and forgetting to add __slots__ should be an error
504
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
505
-
506
473
with KWArgs (kwargs ) as k :
507
474
metadata = k .optional ("metadata" )
508
475
__dict__ = k .optional ("__dict__" )
509
476
options = k .options (
510
477
underflow = True , overflow = True , circular = False , growth = False
511
478
)
512
479
513
- __dict__ = _process_metadata_dict (metadata , __dict__ )
514
-
515
480
# underflow and overflow settings are ignored, integers are always
516
481
# finite and thus cannot end up in a flow bin when growth is on
517
482
if "growth" in options and "circular" not in options :
518
- self . _ax = ca .integer_growth (start , stop )
483
+ ax = ca .integer_growth (start , stop )
519
484
elif options == {"underflow" , "overflow" }:
520
- self . _ax = ca .integer_uoflow (start , stop )
485
+ ax = ca .integer_uoflow (start , stop )
521
486
elif options == {"underflow" }:
522
- self . _ax = ca .integer_uflow (start , stop )
487
+ ax = ca .integer_uflow (start , stop )
523
488
elif options == {"overflow" }:
524
- self . _ax = ca .integer_oflow (start , stop )
489
+ ax = ca .integer_oflow (start , stop )
525
490
elif "circular" in options and "growth" not in options :
526
- self . _ax = ca .integer_circular (start , stop )
491
+ ax = ca .integer_circular (start , stop )
527
492
elif options == set ():
528
- self . _ax = ca .integer_none (start , stop )
493
+ ax = ca .integer_none (start , stop )
529
494
else :
530
495
raise KeyError ("Unsupported collection of options" )
531
496
532
- self . _ax . metadata = __dict__
497
+ super ( Integer , self ). __init__ ( ax , metadata , __dict__ )
533
498
534
499
def _repr_args (self ):
535
500
"Return inner part of signature for use in repr"
@@ -586,27 +551,22 @@ def __init__(self, categories, **kwargs):
586
551
The full metadata dictionary
587
552
"""
588
553
589
- # Inheriting an axis and forgetting to add __slots__ should be an error
590
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
591
-
592
554
with KWArgs (kwargs ) as k :
593
555
metadata = k .optional ("metadata" )
594
556
__dict__ = k .optional ("__dict__" )
595
557
options = k .options (growth = False )
596
558
597
- __dict__ = _process_metadata_dict (metadata , __dict__ )
598
-
599
559
# henryiii: We currently expand "abc" to "a", "b", "c" - some
600
560
# Python interfaces protect against that
601
561
602
562
if options == {"growth" }:
603
- self . _ax = ca .category_str_growth (tuple (categories ))
563
+ ax = ca .category_str_growth (tuple (categories ))
604
564
elif options == set ():
605
- self . _ax = ca .category_str (tuple (categories ))
565
+ ax = ca .category_str (tuple (categories ))
606
566
else :
607
567
raise KeyError ("Unsupported collection of options" )
608
568
609
- self . _ax . metadata = __dict__
569
+ super ( StrCategory , self ). __init__ ( ax , metadata , __dict__ )
610
570
611
571
def index (self , value ):
612
572
"""
@@ -655,24 +615,19 @@ def __init__(self, categories, **kwargs):
655
615
The full metadata dictionary
656
616
"""
657
617
658
- # Inheriting an axis and forgetting to add __slots__ should be an error
659
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
660
-
661
618
with KWArgs (kwargs ) as k :
662
619
metadata = k .optional ("metadata" )
663
620
__dict__ = k .optional ("__dict__" )
664
621
options = k .options (growth = False )
665
622
666
- __dict__ = _process_metadata_dict (metadata , __dict__ )
667
-
668
623
if options == {"growth" }:
669
- self . _ax = ca .category_int_growth (tuple (categories ))
624
+ ax = ca .category_int_growth (tuple (categories ))
670
625
elif options == set ():
671
- self . _ax = ca .category_int (tuple (categories ))
626
+ ax = ca .category_int (tuple (categories ))
672
627
else :
673
628
raise KeyError ("Unsupported collection of options" )
674
629
675
- self . _ax . metadata = __dict__
630
+ super ( IntCategory , self ). __init__ ( ax , metadata , __dict__ )
676
631
677
632
def _repr_args (self ):
678
633
"Return inner part of signature for use in repr"
@@ -700,17 +655,13 @@ def __init__(self, **kwargs):
700
655
The full metadata dictionary
701
656
"""
702
657
703
- # Inheriting an axis and forgetting to add __slots__ should be an error
704
- assert not hasattr (self , "__weakref__" ), "Axis subclasses must have __slots__!"
705
-
706
658
with KWArgs (kwargs ) as k :
707
659
metadata = k .optional ("metadata" )
708
660
__dict__ = k .optional ("__dict__" )
709
661
710
- __dict__ = _process_metadata_dict ( metadata , __dict__ )
662
+ ax = ca . boolean ( )
711
663
712
- self ._ax = ca .boolean ()
713
- self ._ax .metadata = __dict__
664
+ super (Boolean , self ).__init__ (ax , metadata , __dict__ )
714
665
715
666
def _repr_args (self ):
716
667
"Return inner part of signature for use in repr"
0 commit comments