classicist 1.0.3__py3-none-any.whl → 1.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
classicist/__init__.py CHANGED
@@ -1,20 +1,39 @@
1
- # Decorator Classes
1
+ # Decorators
2
2
  from classicist.decorators import (
3
+ # @alias decorator
3
4
  alias,
4
- annotate,
5
+ # @annotation decorator
5
6
  annotation,
6
- annotations,
7
+ # @classproperty decorator
7
8
  classproperty,
9
+ # @deprecated decorator
8
10
  deprecated,
11
+ # @hybridmethod decorator
9
12
  hybridmethod,
13
+ # @nocache decorator
10
14
  nocache,
15
+ # @runtimer decorator
16
+ runtimer,
11
17
  )
12
18
 
13
19
  # Decorator Helper Methods
14
20
  from classicist.decorators import (
21
+ # @alias decorator helper methods
15
22
  is_aliased,
16
23
  aliases,
24
+ # @annotation decorator helper methods
25
+ annotate,
26
+ annotations,
27
+ # @deprecated decorator helper methods
17
28
  is_deprecated,
29
+ # @runtimer decorator helper methods
30
+ runtime,
31
+ has_runtimer,
32
+ )
33
+
34
+ # Decorator Related Classes
35
+ from classicist.decorators import (
36
+ Runtimer,
18
37
  )
19
38
 
20
39
  # Meta Classes
@@ -25,9 +44,16 @@ from classicist.metaclasses import (
25
44
 
26
45
  # Exception Classes
27
46
  from classicist.exceptions import (
47
+ AliasError,
48
+ AnnotationError,
28
49
  AttributeShadowingError,
29
50
  )
30
51
 
52
+ from classicist.types import (
53
+ NullType,
54
+ Null,
55
+ )
56
+
31
57
  __all__ = [
32
58
  # Decorators
33
59
  "alias",
@@ -38,13 +64,23 @@ __all__ = [
38
64
  "deprecated",
39
65
  "hybridmethod",
40
66
  "nocache",
67
+ "runtimer",
41
68
  # Decorator Helper Methods
42
69
  "is_aliased",
43
70
  "aliases",
44
71
  "is_deprecated",
72
+ "runtime",
73
+ "has_runtimer",
74
+ # Decorator Related Classes
75
+ "Runtimer",
45
76
  # Meta Classes
46
77
  "aliased",
47
78
  "shadowproof",
48
79
  # Exception Classes
80
+ "AliasError",
81
+ "AnnotationError",
49
82
  "AttributeShadowingError",
83
+ # Types
84
+ "NullType",
85
+ "Null",
50
86
  ]
@@ -4,6 +4,7 @@ from classicist.decorators.classproperty import classproperty
4
4
  from classicist.decorators.deprecated import deprecated, is_deprecated
5
5
  from classicist.decorators.hybridmethod import hybridmethod
6
6
  from classicist.decorators.nocache import nocache
7
+ from classicist.decorators.runtimer import Runtimer, runtimer, runtime, has_runtimer
7
8
 
8
9
  __all__ = [
9
10
  "alias",
@@ -17,4 +18,8 @@ __all__ = [
17
18
  "is_deprecated",
18
19
  "hybridmethod",
19
20
  "nocache",
21
+ "Runtimer",
22
+ "runtimer",
23
+ "runtime",
24
+ "has_runtimer",
20
25
  ]
@@ -0,0 +1,165 @@
1
+ from __future__ import annotations
2
+
3
+ from datetime import datetime, timedelta
4
+ from functools import wraps
5
+ from inspect import unwrap
6
+
7
+ from classicist.logging import logger
8
+
9
+ logger = logger.getChild(__name__)
10
+
11
+
12
+ class Runtimer(object):
13
+ """The Runtimer class times and tracks the runtime of function calls."""
14
+
15
+ _funcobj: callable = None
16
+ _started: datetime = None
17
+ _stopped: datetime = None
18
+
19
+ def __init__(self, function: callable):
20
+ """Supports instantiating an instance of the Runtimer class."""
21
+
22
+ if not callable(function):
23
+ raise TypeError("The 'function' argument must reference a callable!")
24
+
25
+ self._funcobj = function
26
+
27
+ def __str__(self) -> str:
28
+ """Returns a string representation of the current Runtimer instance."""
29
+
30
+ return f"<{self.__class__.__name__}(started: {self.started}, stopped: {self.stopped}, duration: {self.duration})>"
31
+
32
+ def __repr__(self) -> str:
33
+ """Returns a debug string representation of the current Runtimer instance."""
34
+
35
+ return f"<{self.__class__.__name__}(started: {self.started}, stopped: {self.stopped}, duration: {self.duration}) @ {hex(id(self))}>"
36
+
37
+ def reset(self) -> Runtimer:
38
+ """Supports resetting the Runtimer timing information."""
39
+
40
+ self._started = None
41
+ self._stopped = None
42
+
43
+ return self
44
+
45
+ def start(self) -> Runtimer:
46
+ """Supports starting the Runtimer timer by recording the current datetime."""
47
+
48
+ self._started = datetime.now()
49
+ self._stopped = None
50
+
51
+ return self
52
+
53
+ def stop(self) -> Runtimer:
54
+ """Supports stopping the Runtimer timer by recording the current datetime."""
55
+
56
+ if self._started is None:
57
+ self._started = datetime.now()
58
+ self._stopped = datetime.now()
59
+
60
+ return self
61
+
62
+ @property
63
+ def function(self) -> callable:
64
+ """Supports returning the Runtimer instance's associated function/method."""
65
+
66
+ return self._funcobj
67
+
68
+ @property
69
+ def started(self) -> datetime:
70
+ """Supports returning the started datetime or the current time as a fallback."""
71
+
72
+ return self._started or datetime.now()
73
+
74
+ @property
75
+ def stopped(self) -> datetime:
76
+ """Supports returning the stopped datetime or the current time as a fallback."""
77
+
78
+ return self._stopped or datetime.now()
79
+
80
+ @property
81
+ def timedelta(self) -> timedelta:
82
+ """Supports returning the timedelta for the decorated function's call time."""
83
+
84
+ if isinstance(self._started, datetime) and isinstance(self._stopped, datetime):
85
+ return self._stopped - self._started
86
+ else:
87
+ return timedelta(0)
88
+
89
+ @property
90
+ def duration(self) -> float:
91
+ """Supports returning the duration of the decorated function's call time."""
92
+
93
+ return self.timedelta.total_seconds()
94
+
95
+
96
+ def runtimer(function: callable) -> callable:
97
+ """The runtimer decorator method creates an instance of the Runtimer class for the
98
+ specified function, allowing calls to the function to be timed."""
99
+
100
+ if not callable(function):
101
+ raise TypeError("The 'function' argument must reference a callable!")
102
+
103
+ logger.debug("runtimer(function: %s)", function)
104
+
105
+ # If the function already has an associated Runtimer instance, reset it
106
+ if isinstance(
107
+ _runtimer := getattr(function, "_classicist_runtimer", None), Runtimer
108
+ ):
109
+ _runtimer.reset()
110
+ else:
111
+ # Otherwise, create a new instance and associate it with the function
112
+ _runtimer = function._classicist_runtimer = Runtimer(function)
113
+
114
+ @wraps(function)
115
+ def wrapper(*args, **kwargs):
116
+ logger.debug(
117
+ "runtimer(function: %s).wrapper(args: %s, kwargs: %s)",
118
+ function,
119
+ args,
120
+ kwargs,
121
+ )
122
+
123
+ _runtimer.start()
124
+ result = function(*args, **kwargs)
125
+ _runtimer.stop()
126
+
127
+ return result
128
+
129
+ return wrapper
130
+
131
+
132
+ def runtime(function: callable) -> Runtimer | None:
133
+ """The runtime helper method can be used to obtain the Runtimer instance for the
134
+ specified function, if one is present, allowing access to the most recent function
135
+ call start and stop time stamps and call duration."""
136
+
137
+ if not callable(function):
138
+ raise TypeError("The 'function' argument must reference a callable!")
139
+
140
+ function = unwrap(function)
141
+
142
+ logger.debug("runtime(function: %s)" % (function))
143
+
144
+ if isinstance(
145
+ _runtimer := getattr(function, "_classicist_runtimer", None), Runtimer
146
+ ):
147
+ return _runtimer
148
+
149
+
150
+ def has_runtimer(function: callable) -> bool:
151
+ """The has_runtimer helper method can be used to determine if the specified function
152
+ has an associated Runtimer instance or not, returning a boolean to indicate this."""
153
+
154
+ if isinstance(getattr(function, "_classicist_runtimer", None), Runtimer):
155
+ return True
156
+ else:
157
+ return False
158
+
159
+
160
+ __all__ = [
161
+ "Runtimer",
162
+ "runtimer",
163
+ "runtime",
164
+ "hasruntimer",
165
+ ]
@@ -1,4 +1,5 @@
1
1
  from classicist.exceptions.decorators import (
2
+ AliasError,
2
3
  AnnotationError,
3
4
  )
4
5
 
@@ -7,6 +8,7 @@ from classicist.exceptions.metaclasses import (
7
8
  )
8
9
 
9
10
  __all__ = [
11
+ "AliasError",
10
12
  "AnnotationError",
11
13
  "AttributeShadowingError",
12
14
  ]
@@ -0,0 +1,6 @@
1
+ from classicist.types.null import NullType, Null
2
+
3
+ __all__ = [
4
+ "NullType",
5
+ "Null",
6
+ ]
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ class NullType(object):
5
+ """The NullType class supports the creation of a Null singleton instance that offers
6
+ support for safely chaining nested attribute accesses without raising exceptions for
7
+ attributes that have no inherent value.
8
+
9
+ As Python currently lacks a null-aware navigation operator, such as `?.`, like many
10
+ other dynamic languages, for safely navigating nested object hierarchies which may
11
+ contain null attributes, the library offers the `NullType` and `Null` singleton as a
12
+ potential option to support this need in the interim. Consistent use of the `Null`
13
+ singleton in place of the standard `None` singleton, in relevant scenarios, such as
14
+ within a data model library for example, can allow for more expressive and clearer
15
+ code that does not require endless checks for intermediary attribute existence.
16
+
17
+ However, there are some caveats to the use of the `NullType` and `Null` singleton as
18
+ these are not built-in features of the language, and Python does not offer support
19
+ for the creation of custom operators nor overriding the `is` operator for identity
20
+ checking which limits some of the cases in which the `Null` singleton could be used.
21
+
22
+ With knowledge of the caveats and in the right scenarios, the `Null` singleton can
23
+ offer a good way to achieve clearer and more expressive code while navigating nested
24
+ object hierarchies without the clutter of nested attribute existence checks."""
25
+
26
+ _instance: NullType = None
27
+
28
+ def __new__(cls) -> NullType:
29
+ """Ensure NullType can only create a singleton instance; further calls to create
30
+ instances of the NullType will return the existing singleton instance."""
31
+
32
+ if cls._instance is None:
33
+ cls._instance = super().__new__(cls)
34
+
35
+ return cls._instance
36
+
37
+ def __getattr__(self, name: str) -> NullType:
38
+ """Support nested attribute access by returning the singleton instance."""
39
+
40
+ return self.__class__._instance
41
+
42
+ def __bool__(self) -> bool:
43
+ """Support falsey equality checks for boolean comparisons against NullType."""
44
+
45
+ return False # Always returns False
46
+
47
+ def __eq__(self, value: object) -> bool:
48
+ """Support value equality checks against NullType via the `==` operator as the
49
+ fallback option to being able to support identity equality checks via the `is`
50
+ operator which are not currently possible due to language constraints."""
51
+
52
+ if value is None or value is False:
53
+ return True
54
+ else:
55
+ return self is value
56
+
57
+ def __str__(self) -> str:
58
+ return "Null"
59
+
60
+ def __repr__(self) -> str:
61
+ return "Null"
62
+
63
+
64
+ # Create the singleton instance of Null
65
+ Null = NullType()
66
+
67
+ __all__ = [
68
+ "NullType",
69
+ "Null",
70
+ ]
classicist/version.txt CHANGED
@@ -1 +1 @@
1
- 1.0.3
1
+ 1.0.5
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: classicist
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: Classy class decorators for Python.
5
5
  Author: Daniel Sissman
6
6
  License-Expression: MIT
@@ -33,16 +33,20 @@ Dynamic: license-file
33
33
 
34
34
  # Classicist: Classy Class Decorators & Extensions
35
35
 
36
- The Classicist library provides several useful decorators and helper methods including:
36
+ The Classicist library provides several useful decorators, functions, classes, and types
37
+ that offer useful behaviours and functionality, and help to fill some of the gaps in the
38
+ current standard library:
37
39
 
38
40
  * `@hybridmethod` – a decorator that allows methods to be used both as class methods and as instance methods;
39
- * `@classproperty` – a decorator that allow class methods to be accessed as class properties;
41
+ * `@classproperty` – a decorator that allows class methods to be accessed as class properties;
40
42
  * `@annotation` – a decorator that can be used to apply arbitrary annotations to code objects;
41
- * `@deprecated` – a decorator that can be used to mark functions, classes and methods as being deprecated;
43
+ * `@deprecated` – a decorator that can be used to mark functions, classes and methods as being deprecated, with support for adding optional arbitrary annotations;
42
44
  * `@alias` – a decorator that can be used to add aliases to classes, methods defined within classes, module-level functions, and nested functions when overriding the aliasing scope;
43
45
  * `@nocache` – a decorator that can be used to mark functions and methods as not being suitable for caching;
46
+ * `@runtimer` – a decorator that can be used to gather call run time information for function and method calls;
44
47
  * `shadowproof` – a metaclass that can be used to protect subclasses from class-level attributes
45
- being overwritten (or shadowed) which can otherwise negatively affect class behaviour in some cases.
48
+ being overwritten (or shadowed) which can otherwise negatively affect class behaviour in some cases;
49
+ * `Null` – an alternative to `None`, useful when building custom data model classes and libraries, where supporting "null-safe" style access and navigation of the model's nested hierarchy is preferred.
46
50
 
47
51
  The `classicist` library was previously named `hybridmethod` so if a prior version had
48
52
  been installed, please update references to the new library name. Installation of the
@@ -482,6 +486,48 @@ class Test(object):
482
486
  pass
483
487
  ```
484
488
 
489
+ #### Runtimer: Function & Method Call Timing
490
+
491
+ The `@runtimer` decorator can be used to obtain run times for function and method calls,
492
+ including the start and stop `datetime`, the `timedelta` and the duration in seconds.
493
+
494
+ To collect timing information simply import the `runtimer` decorator from the library,
495
+ and apply it to the function, class method or instance method that you wish to time, and
496
+ after the call has been made, you can obtain the run time information from the function
497
+ or method via the `classicist` library's `runtime` helper method, which provides access
498
+ to an instance of the library's `Runtimer` class which is used to track the run time:
499
+
500
+ ```python
501
+ from classicist import runtimer, runtime, Runtimer
502
+ from datetime import datetime
503
+ from time import sleep
504
+
505
+ @runtimer
506
+ def function_to_time(value: int) -> int:
507
+ sleep(0.01)
508
+ return value * 100
509
+
510
+ # Obtain a reference to the function's Runtimer (created by the @runtimer decorator)
511
+ # This reference can be obtained before or after a call to the decorated function
512
+ runtimer: Runtimer = runtime(function_to_time)
513
+ assert isinstance(runtimer, Runtimer)
514
+
515
+ # Obtain the time before the function call for illustrative purposes (not needed in use)
516
+ started: datetime = datetime.now()
517
+
518
+ # Call the method to perform its work, and its runtime will be gathered
519
+ assert function_to_time(2) == 200
520
+
521
+ # Obtain the time after the function call for illustrative purposes (not needed in use)
522
+ stopped: datetime = datetime.now()
523
+
524
+ # Use the gathered runtime information as needed
525
+ assert runtimer.started > started
526
+ assert runtimer.duration >= 0.01
527
+ assert runtimer.timedelta.total_seconds() >= 0.01
528
+ assert runtimer.stopped < stopped
529
+ ```
530
+
485
531
  #### ShadowProof: Attribute Shadowing Protection Metaclass
486
532
 
487
533
  The `shadowproof` metaclass can be used to protect classes and subclasses from attribute
@@ -511,6 +557,146 @@ except AttributeShadowingError as exception:
511
557
  pass
512
558
  ```
513
559
 
560
+ #### NullType: Null-Safe Style Access for Data Models and Nested Class Hierarchies
561
+
562
+ The `NullType` class supports the creation of a `Null` singleton instance that offers
563
+ support for safely chaining nested attribute accesses without raising exceptions for
564
+ attributes that have no inherent value.
565
+
566
+ As Python currently lacks a null-aware navigation operator, such as `?.`, unlike many
567
+ other dynamic languages, for safely navigating nested object hierarchies which may
568
+ contain null attributes, the library offers the `NullType` and `Null` singleton as a
569
+ potential option to support this need in the interim. Consistent use of the `Null`
570
+ singleton in place of the standard `None` singleton, in relevant scenarios, such as
571
+ within a custom data model library, can allow for more expressive and clearer code that
572
+ does not require endless checks for intermediary or nested attribute existence.
573
+
574
+ However, there are some caveats to the use of the `NullType` and `Null` singleton as
575
+ these are not built-in features of the language, and Python does not offer support for
576
+ the creation of custom operators nor overriding the `is` operator for identity checking
577
+ which limits some of the use cases in which the `Null` singleton can be used.
578
+
579
+ With knowledge of these caveats and in the right scenarios, the `Null` singleton can
580
+ offer a good way to achieve clearer and more expressive code while navigating nested
581
+ object hierarchies without the clutter of nested attribute existence checks.
582
+
583
+ ```python
584
+ from __future__ import annotations
585
+
586
+ from classicist import Null
587
+
588
+ data: dict = {
589
+ "id": 1,
590
+ "name": "A",
591
+ "related": {
592
+ "id": 2,
593
+ "name": "B",
594
+ "related": {
595
+ "id": 3,
596
+ "name": "C",
597
+ },
598
+ },
599
+ }
600
+
601
+ class Model(object):
602
+ """Sample Model class with some properties that reference nested Model instances."""
603
+
604
+ def __init__(self, data: dict):
605
+ if not isinstance(data, dict):
606
+ raise TypeError("The 'data' argument must reference a valid data dictionary!")
607
+
608
+ if not ("id" in data and isinstance(data["id"], int)):
609
+ raise ValueError("The 'data' must contain an 'id' key with an integer value!")
610
+
611
+ if not ("name" in data and isinstance(data["name"], str)):
612
+ raise ValueError("The 'data' must contain an 'name' key with an string value!")
613
+
614
+ self.data = data
615
+
616
+ @property
617
+ def id(self) -> int:
618
+ return self.data["id"]
619
+
620
+ @property
621
+ def name(self) -> str:
622
+ return self.data["name"]
623
+
624
+ @property
625
+ def related(self) -> Model | Null:
626
+ if data := self.data.get("related"):
627
+ return Model(data=data)
628
+ else:
629
+ return Null
630
+
631
+ @property
632
+ def relates(self) -> Model | Null:
633
+ if data := self.data.get("relates"):
634
+ return Model(data=data)
635
+ else:
636
+ return Null
637
+
638
+ # Create an instance of the sample Model data class
639
+ model = Model(data=data)
640
+
641
+ # Check that the expected data attributes are available
642
+ assert model.id == 1
643
+ assert model.name == "A"
644
+
645
+ # The model.related property references A/1 in the data above, so these properties exist
646
+ assert model.related
647
+ assert model.related.id
648
+ assert model.related.name
649
+
650
+ # Ensure the nested property values are as expected
651
+ assert model.related.id == 2
652
+ assert model.related.name == "B"
653
+
654
+ # Note that model.relates had no corresponding data, so the Model returns `Null` which
655
+ # still allows for nested attribute access, such as to `.id` and `.name` without raising
656
+ # any exceptions; the `Null` singleton also allows for `bool` comparison as shown below:
657
+ assert not model.relates
658
+ assert not model.relates.id
659
+ assert not model.relates.name
660
+
661
+ # There is no limit to the levels of nesting that `NullType` and the `Null` singleton
662
+ # can support, so long as a custom data model or library consistently returns `Null` for
663
+ # cases where the "null-safe" navigation is desired:
664
+
665
+ # model.related.related references 3/C in the data above, so these properties exist
666
+ assert model.related.related.id
667
+ assert model.related.related.name
668
+
669
+ # model.related.relates was not specified in the data above so the Model returns `Null`
670
+ assert not model.related.relates.id
671
+ assert not model.related.relates.name
672
+
673
+ # Ensure the nested property values are as expected
674
+ assert model.related.related.id == 3
675
+ assert model.related.related.name == "C"
676
+
677
+ # These features make it easy to write clearer more expressive code without boilerplate
678
+ # code to check for the availability of nested attributes or entities:
679
+ if isinstance(name := model.related.name, str):
680
+ print("model.related.name => %s" % (name))
681
+
682
+ # No exception is raised here even though model.relates is effectively "null":
683
+ if isinstance(name := model.relates.name, str):
684
+ print("model.relates.name => %s" % (name))
685
+
686
+ # However, there are some caveats as noted with `NullType` and the `Null` singleton as
687
+ # these are a third-party solution so we can only go so far in supplementing null-safe
688
+ # operator behaviour in the language; for example, we cannot perform identity checks to
689
+ # boolean values, True or False, or the actual None singleton value:
690
+ assert not model.relates is True # Notice the `assert not` as `assert` would fail here
691
+ assert not model.relates is False # Notice the `assert not` as `assert` would fail here
692
+
693
+ # Furthermore, we cannot use `None` identity comparison either:
694
+ assert not model.relates is None # Notice the `assert not` as `assert` would fail here
695
+
696
+ # We can however perform an identity check against the `Null` singleton if needed:
697
+ assert model.relates is Null
698
+ ```
699
+
514
700
  ### Unit Tests
515
701
 
516
702
  The Classicist library includes a suite of comprehensive unit tests which ensure that
@@ -1,13 +1,14 @@
1
- classicist/__init__.py,sha256=Rkm1Vx0Z-BHPH1FSzFLrAxwkFEt1xvMxZz-mC8FJSDc,834
2
- classicist/version.txt,sha256=INLLCW0atBpBQCRtEvB79rjLdD_UgSK3JTLAPUTFwUo,5
3
- classicist/decorators/__init__.py,sha256=wplcs2JnyGMOh72626-x-WyVotVoT7nvk-dpjeTXQ88,600
1
+ classicist/__init__.py,sha256=VeAO1fY3noKmFJDdiCFUABIykF3oXSk_9QXNSaaXIp0,1584
2
+ classicist/version.txt,sha256=nXE_EpedYoeSULwKIDXj71cxWsQlHoUBnSHHXtcmlyA,5
3
+ classicist/decorators/__init__.py,sha256=Cz1zXWoLV7s63pQiOQX6B0RGDOg3schTbtkq6THz3J8,752
4
4
  classicist/decorators/aliased/__init__.py,sha256=vW1P9jbGkOD_m9GvgEXF0Uni-Dt6rfVXDVF5D4wC1GY,6926
5
5
  classicist/decorators/annotation/__init__.py,sha256=20WwmrXDxT85sItpDiCdC-hZjbyDR6E2mLPMSKQgm8g,1796
6
6
  classicist/decorators/classproperty/__init__.py,sha256=ED37_20UeAGKX1ahsv16wTg0JAJT4UBLqiNRbKAp2KE,1646
7
7
  classicist/decorators/deprecated/__init__.py,sha256=aAPFQoT-pJf1nauQGiPADkPBREMvEQJaUQc3kjA48Rg,2764
8
8
  classicist/decorators/hybridmethod/__init__.py,sha256=uEsp54ZL0UESAbhIigLtzOg_DHupr9EohzZaL5VYJzY,2512
9
9
  classicist/decorators/nocache/__init__.py,sha256=0S2yToD_PjShQK8RZ_MZRBtBxGM6hegtDSIPbZlq4vw,287
10
- classicist/exceptions/__init__.py,sha256=JTo3DDfvL8eex0H5erL8Yd9pQL6B1l3nPXcCapcCWLs,219
10
+ classicist/decorators/runtimer/__init__.py,sha256=3yoWDKzpq7IHrQJG2QMkUZOQmW4rtxmlM_mMC2N5V_8,4999
11
+ classicist/exceptions/__init__.py,sha256=P4sVGQ5wn2wdNLAhKDBKfTX4Vgell6sPlAQhadcOJxw,253
11
12
  classicist/exceptions/decorators/__init__.py,sha256=YSpu4-sX0QKbLf0ZpNFS3hXA9pPOo3uoMgAFvRT3emc,192
12
13
  classicist/exceptions/decorators/aliased/__init__.py,sha256=ea8Q9TQ80r0DeRMBbJ9VX9Y3y00iTLYiuB2KEkW4ajw,43
13
14
  classicist/exceptions/decorators/annotation/__init__.py,sha256=nogEgpDo5lnEG7IC2kR4Pb_BORu6Cubik4LlcnCSg-g,48
@@ -18,9 +19,11 @@ classicist/logging/__init__.py,sha256=LJ-Nih1LacPrO2TvTT6l84So-pgw84AHJ8IhzYKl5r
18
19
  classicist/metaclasses/__init__.py,sha256=mYhR5rM7cnJlaNUlgoQWOo44RQSORteRjYd0y0BajxQ,159
19
20
  classicist/metaclasses/aliased/__init__.py,sha256=grs4Z8dMY6R2fCFn4UCPdCzEJtVaAv-tsWFwY1DCUpI,2033
20
21
  classicist/metaclasses/shadowproof/__init__.py,sha256=d55uNjcaCorD3MdDUv7aRVpk2MlE8JzMjint6Vvf_Yc,1492
21
- classicist-1.0.3.dist-info/licenses/LICENSE.md,sha256=qBmrjPmSCp0YFyaIl2G3FU3rniFD31YC0Yd3MrO1wEg,1070
22
- classicist-1.0.3.dist-info/METADATA,sha256=iZaQqjD9wd84Bb_Dx_Se-RMYgZTvvf2Hkf2idrnswgk,25128
23
- classicist-1.0.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
24
- classicist-1.0.3.dist-info/top_level.txt,sha256=beG3ZuwObnmnY_mgNSN5CaVIWpI2VKszjVdKHPgZBhc,11
25
- classicist-1.0.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
26
- classicist-1.0.3.dist-info/RECORD,,
22
+ classicist/types/__init__.py,sha256=EZE6NnKf051F5MuqxyReJb4oHIzQY2gCgOxC51_64mI,92
23
+ classicist/types/null/__init__.py,sha256=cY7eFop17KuuXO-1eqxXl1RGsAHASFKlpx5f7JXv00E,2829
24
+ classicist-1.0.5.dist-info/licenses/LICENSE.md,sha256=qBmrjPmSCp0YFyaIl2G3FU3rniFD31YC0Yd3MrO1wEg,1070
25
+ classicist-1.0.5.dist-info/METADATA,sha256=n9Dm7Vj8iWqws1XiuvRViMqoqsYiAV2gpCqvAGu0MEc,32691
26
+ classicist-1.0.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
27
+ classicist-1.0.5.dist-info/top_level.txt,sha256=beG3ZuwObnmnY_mgNSN5CaVIWpI2VKszjVdKHPgZBhc,11
28
+ classicist-1.0.5.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
29
+ classicist-1.0.5.dist-info/RECORD,,