@@ -30,35 +30,52 @@ def _isstr(value):
30
30
# Contains common methods and properties to all axes
31
31
@set_module ("boost_histogram.axis" )
32
32
class Axis (object ):
33
- __slots__ = ("_ax" ,)
33
+ __slots__ = ("_ax" , "__dict__" )
34
34
35
- def __copy__ (self ):
36
- other = self . __class__ . __new__ ( self . __class__ )
37
- other . _ax = copy . copy ( self ._ax )
38
- return other
35
+ def __setattr__ (self , attr , value ):
36
+ if attr == "__dict__" :
37
+ self ._ax . metadata = value
38
+ object . __setattr__ ( self , attr , value )
39
39
40
- def __getattr__ (self , item ):
41
- if item == "_ax" :
42
- return Axis .__dict__ [item ].__get__ (self )
43
- elif item in self ._ax .metadata :
44
- return self ._ax .metadata [item ]
45
- elif item == "metadata" :
40
+ def __getattr__ (self , attr ):
41
+ if attr == "metadata" :
46
42
return None
47
- else :
48
- msg = "'{}' object has no attribute '{}' in {}" .format (
49
- type (self ).__name__ , item , set (self ._ax .metadata )
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
+ """
53
+
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"
50
59
)
51
- raise AttributeError (msg )
60
+ elif __dict__ is not None :
61
+ self ._ax .metadata = __dict__
62
+ elif metadata is not None :
63
+ self ._ax .metadata ["metadata" ] = metadata
52
64
53
- def __setattr__ (self , item , value ):
54
- if item == "_ax" :
55
- Axis .__dict__ [item ].__set__ (self , value )
56
- else :
57
- self ._ax .metadata [item ] = value
65
+ self .__dict__ = self ._ax .metadata
66
+
67
+ def __setstate__ (self , state ):
68
+ self ._ax = state ["_ax" ]
69
+ self .__dict__ = self ._ax .metadata
70
+
71
+ def __getstate__ (self ):
72
+ return {"_ax" : self ._ax }
58
73
59
- def __dir__ (self ):
60
- metadata = list (self ._ax .metadata )
61
- return sorted (dir (type (self )) + metadata )
74
+ def __copy__ (self ):
75
+ other = self .__class__ .__new__ (self .__class__ )
76
+ other ._ax = copy .copy (self ._ax )
77
+ other .__dict__ = other ._ax .metadata
78
+ return other
62
79
63
80
def index (self , value ):
64
81
"""
@@ -100,6 +117,7 @@ def __ne__(self, other):
100
117
def _convert_cpp (cls , cpp_object ):
101
118
nice_ax = cls .__new__ (cls )
102
119
nice_ax ._ax = cpp_object
120
+ nice_ax .__dict__ = cpp_object .metadata
103
121
return nice_ax
104
122
105
123
def __len__ (self ):
@@ -230,7 +248,7 @@ class Regular(Axis):
230
248
__slots__ = ()
231
249
232
250
@inject_signature (
233
- "self, bins, start, stop, *, metadata=None, underflow=True, overflow=True, growth=False, circular=False, transform=None"
251
+ "self, bins, start, stop, *, metadata=None, underflow=True, overflow=True, growth=False, circular=False, transform=None, __dict__=None "
234
252
)
235
253
def __init__ (self , bins , start , stop , ** kwargs ):
236
254
"""
@@ -258,11 +276,14 @@ def __init__(self, bins, start, stop, **kwargs):
258
276
Filling wraps around.
259
277
transform : Optional[AxisTransform] = None
260
278
Transform the regular bins (Log, Sqrt, and Pow(v))
279
+ __dict__: Optional[Dict[str, Any]] = None
280
+ The full metadata dictionary
261
281
"""
262
282
263
283
with KWArgs (kwargs ) as k :
264
284
metadata = k .optional ("metadata" )
265
285
transform = k .optional ("transform" )
286
+ __dict__ = k .optional ("__dict__" )
266
287
options = k .options (
267
288
underflow = True , overflow = True , growth = False , circular = False
268
289
)
@@ -277,29 +298,29 @@ def __init__(self, bins, start, stop, **kwargs):
277
298
):
278
299
raise TypeError ("You must pass an instance, use {}()" .format (transform ))
279
300
280
- self . _ax = transform ._produce (bins , start , stop )
301
+ ax = transform ._produce (bins , start , stop )
281
302
282
303
elif options == {"growth" , "underflow" , "overflow" }:
283
- self . _ax = ca .regular_uoflow_growth (bins , start , stop )
304
+ ax = ca .regular_uoflow_growth (bins , start , stop )
284
305
elif options == {"underflow" , "overflow" }:
285
- self . _ax = ca .regular_uoflow (bins , start , stop )
306
+ ax = ca .regular_uoflow (bins , start , stop )
286
307
elif options == {"underflow" }:
287
- self . _ax = ca .regular_uflow (bins , start , stop )
308
+ ax = ca .regular_uflow (bins , start , stop )
288
309
elif options == {"overflow" }:
289
- self . _ax = ca .regular_oflow (bins , start , stop )
310
+ ax = ca .regular_oflow (bins , start , stop )
290
311
elif options == {"circular" , "underflow" , "overflow" } or options == {
291
312
"circular" ,
292
313
"overflow" ,
293
314
}:
294
315
# growth=True, underflow=False is also correct
295
- self . _ax = ca .regular_circular (bins , start , stop )
316
+ ax = ca .regular_circular (bins , start , stop )
296
317
297
318
elif options == set ():
298
- self . _ax = ca .regular_none (bins , start , stop )
319
+ ax = ca .regular_none (bins , start , stop )
299
320
else :
300
321
raise KeyError ("Unsupported collection of options" )
301
322
302
- self . metadata = metadata
323
+ super ( Regular , self ). __init__ ( ax , metadata , __dict__ )
303
324
304
325
def _repr_args (self ):
305
326
"Return inner part of signature for use in repr"
@@ -339,7 +360,7 @@ class Variable(Axis):
339
360
__slots__ = ()
340
361
341
362
@inject_signature (
342
- "self, edges, *, metadata=None, underflow=True, overflow=True, growth=False"
363
+ "self, edges, *, metadata=None, underflow=True, overflow=True, growth=False, __dict__=None "
343
364
)
344
365
def __init__ (self , edges , ** kwargs ):
345
366
"""
@@ -361,33 +382,37 @@ def __init__(self, edges, **kwargs):
361
382
growth : bool = False
362
383
Allow the axis to grow if a value is encountered out of range.
363
384
Be careful, the axis will grow as large as needed.
385
+ __dict__: Optional[Dict[str, Any]] = None
386
+ The full metadata dictionary
364
387
"""
388
+
365
389
with KWArgs (kwargs ) as k :
366
390
metadata = k .optional ("metadata" )
391
+ __dict__ = k .optional ("__dict__" )
367
392
options = k .options (
368
393
underflow = True , overflow = True , circular = False , growth = False
369
394
)
370
395
371
396
if options == {"growth" , "underflow" , "overflow" }:
372
- self . _ax = ca .variable_uoflow_growth (edges )
397
+ ax = ca .variable_uoflow_growth (edges )
373
398
elif options == {"underflow" , "overflow" }:
374
- self . _ax = ca .variable_uoflow (edges )
399
+ ax = ca .variable_uoflow (edges )
375
400
elif options == {"underflow" }:
376
- self . _ax = ca .variable_uflow (edges )
401
+ ax = ca .variable_uflow (edges )
377
402
elif options == {"overflow" }:
378
- self . _ax = ca .variable_oflow (edges )
403
+ ax = ca .variable_oflow (edges )
379
404
elif options == {"circular" , "underflow" , "overflow" ,} or options == {
380
405
"circular" ,
381
406
"overflow" ,
382
407
}:
383
408
# growth=True, underflow=False is also correct
384
- self . _ax = ca .variable_circular (edges )
409
+ ax = ca .variable_circular (edges )
385
410
elif options == set ():
386
- self . _ax = ca .variable_none (edges )
411
+ ax = ca .variable_none (edges )
387
412
else :
388
413
raise KeyError ("Unsupported collection of options" )
389
414
390
- self . metadata = metadata
415
+ super ( Variable , self ). __init__ ( ax , metadata , __dict__ )
391
416
392
417
def _repr_args (self ):
393
418
"Return inner part of signature for use in repr"
@@ -414,7 +439,7 @@ class Integer(Axis):
414
439
__slots__ = ()
415
440
416
441
@inject_signature (
417
- "self, start, stop, *, metadata=None, underflow=True, overflow=True, growth=False"
442
+ "self, start, stop, *, metadata=None, underflow=True, overflow=True, growth=False, __dict__=None "
418
443
)
419
444
def __init__ (self , start , stop , ** kwargs ):
420
445
"""
@@ -437,31 +462,35 @@ def __init__(self, start, stop, **kwargs):
437
462
growth : bool = False
438
463
Allow the axis to grow if a value is encountered out of range.
439
464
Be careful, the axis will grow as large as needed.
465
+ __dict__: Optional[Dict[str, Any]] = None
466
+ The full metadata dictionary
440
467
"""
468
+
441
469
with KWArgs (kwargs ) as k :
442
470
metadata = k .optional ("metadata" )
471
+ __dict__ = k .optional ("__dict__" )
443
472
options = k .options (
444
473
underflow = True , overflow = True , circular = False , growth = False
445
474
)
446
475
447
476
# underflow and overflow settings are ignored, integers are always
448
477
# finite and thus cannot end up in a flow bin when growth is on
449
478
if "growth" in options and "circular" not in options :
450
- self . _ax = ca .integer_growth (start , stop )
479
+ ax = ca .integer_growth (start , stop )
451
480
elif options == {"underflow" , "overflow" }:
452
- self . _ax = ca .integer_uoflow (start , stop )
481
+ ax = ca .integer_uoflow (start , stop )
453
482
elif options == {"underflow" }:
454
- self . _ax = ca .integer_uflow (start , stop )
483
+ ax = ca .integer_uflow (start , stop )
455
484
elif options == {"overflow" }:
456
- self . _ax = ca .integer_oflow (start , stop )
485
+ ax = ca .integer_oflow (start , stop )
457
486
elif "circular" in options and "growth" not in options :
458
- self . _ax = ca .integer_circular (start , stop )
487
+ ax = ca .integer_circular (start , stop )
459
488
elif options == set ():
460
- self . _ax = ca .integer_none (start , stop )
489
+ ax = ca .integer_none (start , stop )
461
490
else :
462
491
raise KeyError ("Unsupported collection of options" )
463
492
464
- self . metadata = metadata
493
+ super ( Integer , self ). __init__ ( ax , metadata , __dict__ )
465
494
466
495
def _repr_args (self ):
467
496
"Return inner part of signature for use in repr"
@@ -495,7 +524,9 @@ def _repr_kwargs(self):
495
524
@set_module ("boost_histogram.axis" )
496
525
@register ({ca .category_str_growth , ca .category_str })
497
526
class StrCategory (BaseCategory ):
498
- @inject_signature ("self, categories, *, metadata=None, growth=False" )
527
+ __slots__ = ()
528
+
529
+ @inject_signature ("self, categories, *, metadata=None, growth=False, __dict__=None" )
499
530
def __init__ (self , categories , ** kwargs ):
500
531
"""
501
532
Make a category axis with strings; items will
@@ -512,22 +543,26 @@ def __init__(self, categories, **kwargs):
512
543
growth : bool = False
513
544
Allow the axis to grow if a value is encountered out of range.
514
545
Be careful, the axis will grow as large as needed.
546
+ __dict__: Optional[Dict[str, Any]] = None
547
+ The full metadata dictionary
515
548
"""
549
+
516
550
with KWArgs (kwargs ) as k :
517
551
metadata = k .optional ("metadata" )
552
+ __dict__ = k .optional ("__dict__" )
518
553
options = k .options (growth = False )
519
554
520
555
# henryiii: We currently expand "abc" to "a", "b", "c" - some
521
556
# Python interfaces protect against that
522
557
523
558
if options == {"growth" }:
524
- self . _ax = ca .category_str_growth (tuple (categories ))
559
+ ax = ca .category_str_growth (tuple (categories ))
525
560
elif options == set ():
526
- self . _ax = ca .category_str (tuple (categories ))
561
+ ax = ca .category_str (tuple (categories ))
527
562
else :
528
563
raise KeyError ("Unsupported collection of options" )
529
564
530
- self . metadata = metadata
565
+ super ( StrCategory , self ). __init__ ( ax , metadata , __dict__ )
531
566
532
567
def index (self , value ):
533
568
"""
@@ -553,7 +588,9 @@ def _repr_args(self):
553
588
@set_module ("boost_histogram.axis" )
554
589
@register ({ca .category_int , ca .category_int_growth })
555
590
class IntCategory (BaseCategory ):
556
- @inject_signature ("self, categories, *, metadata=None, growth=False" )
591
+ __slots__ = ()
592
+
593
+ @inject_signature ("self, categories, *, metadata=None, growth=False, __dict__=None" )
557
594
def __init__ (self , categories , ** kwargs ):
558
595
"""
559
596
Make a category axis with ints; items will
@@ -570,19 +607,23 @@ def __init__(self, categories, **kwargs):
570
607
growth : bool = False
571
608
Allow the axis to grow if a value is encountered out of range.
572
609
Be careful, the axis will grow as large as needed.
610
+ __dict__: Optional[Dict[str, Any]] = None
611
+ The full metadata dictionary
573
612
"""
613
+
574
614
with KWArgs (kwargs ) as k :
575
615
metadata = k .optional ("metadata" )
616
+ __dict__ = k .optional ("__dict__" )
576
617
options = k .options (growth = False )
577
618
578
619
if options == {"growth" }:
579
- self . _ax = ca .category_int_growth (tuple (categories ))
620
+ ax = ca .category_int_growth (tuple (categories ))
580
621
elif options == set ():
581
- self . _ax = ca .category_int (tuple (categories ))
622
+ ax = ca .category_int (tuple (categories ))
582
623
else :
583
624
raise KeyError ("Unsupported collection of options" )
584
625
585
- self . metadata = metadata
626
+ super ( IntCategory , self ). __init__ ( ax , metadata , __dict__ )
586
627
587
628
def _repr_args (self ):
588
629
"Return inner part of signature for use in repr"
@@ -597,7 +638,7 @@ def _repr_args(self):
597
638
class Boolean (Axis ):
598
639
__slots__ = ()
599
640
600
- @inject_signature ("self, *, metadata=None" )
641
+ @inject_signature ("self, *, metadata=None, __dict__=None " )
601
642
def __init__ (self , ** kwargs ):
602
643
"""
603
644
Make an axis for boolean values.
@@ -606,12 +647,17 @@ def __init__(self, **kwargs):
606
647
----------
607
648
metadata : object
608
649
Any Python object to attach to the axis, like a label.
650
+ __dict__: Optional[Dict[str, Any]] = None
651
+ The full metadata dictionary
609
652
"""
653
+
610
654
with KWArgs (kwargs ) as k :
611
655
metadata = k .optional ("metadata" )
656
+ __dict__ = k .optional ("__dict__" )
657
+
658
+ ax = ca .boolean ()
612
659
613
- self ._ax = ca .boolean ()
614
- self .metadata = metadata
660
+ super (Boolean , self ).__init__ (ax , metadata , __dict__ )
615
661
616
662
def _repr_args (self ):
617
663
"Return inner part of signature for use in repr"
0 commit comments