basilisk-engine 0.1.51__py3-none-any.whl → 0.1.53__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.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

Files changed (94) hide show
  1. basilisk/__init__.py +27 -27
  2. basilisk/audio/sound.py +40 -40
  3. basilisk/bsk_assets/cube.obj +48 -48
  4. basilisk/collisions/broad/broad_aabb.py +102 -102
  5. basilisk/collisions/broad/broad_bvh.py +137 -137
  6. basilisk/collisions/collider.py +95 -95
  7. basilisk/collisions/collider_handler.py +225 -225
  8. basilisk/collisions/narrow/contact_manifold.py +95 -95
  9. basilisk/collisions/narrow/dataclasses.py +34 -34
  10. basilisk/collisions/narrow/deprecated.py +46 -46
  11. basilisk/collisions/narrow/epa.py +91 -91
  12. basilisk/collisions/narrow/gjk.py +66 -66
  13. basilisk/collisions/narrow/graham_scan.py +24 -24
  14. basilisk/collisions/narrow/helper.py +29 -29
  15. basilisk/collisions/narrow/line_intersections.py +106 -106
  16. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  17. basilisk/config.py +53 -53
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +181 -181
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +168 -168
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +70 -70
  25. basilisk/generic/input_validation.py +82 -82
  26. basilisk/generic/math.py +17 -17
  27. basilisk/generic/matrices.py +35 -35
  28. basilisk/generic/meshes.py +72 -72
  29. basilisk/generic/quat.py +142 -142
  30. basilisk/generic/quat_methods.py +7 -7
  31. basilisk/generic/raycast_result.py +26 -26
  32. basilisk/generic/vec3.py +143 -143
  33. basilisk/input_output/IO_handler.py +91 -91
  34. basilisk/input_output/clock.py +49 -49
  35. basilisk/input_output/keys.py +43 -43
  36. basilisk/input_output/mouse.py +90 -90
  37. basilisk/input_output/path.py +14 -14
  38. basilisk/mesh/cube.py +33 -33
  39. basilisk/mesh/mesh.py +233 -233
  40. basilisk/mesh/mesh_from_data.py +150 -150
  41. basilisk/mesh/model.py +271 -271
  42. basilisk/mesh/narrow_aabb.py +89 -89
  43. basilisk/mesh/narrow_bvh.py +91 -91
  44. basilisk/mesh/narrow_primative.py +23 -23
  45. basilisk/nodes/helper.py +28 -28
  46. basilisk/nodes/node.py +709 -709
  47. basilisk/nodes/node_handler.py +107 -98
  48. basilisk/particles/particle_handler.py +69 -65
  49. basilisk/particles/particle_renderer.py +92 -93
  50. basilisk/physics/impulse.py +112 -112
  51. basilisk/physics/physics_body.py +43 -43
  52. basilisk/physics/physics_engine.py +35 -35
  53. basilisk/render/batch.py +103 -103
  54. basilisk/render/bloom.py +117 -117
  55. basilisk/render/camera.py +260 -260
  56. basilisk/render/chunk.py +113 -113
  57. basilisk/render/chunk_handler.py +167 -167
  58. basilisk/render/frame.py +130 -130
  59. basilisk/render/framebuffer.py +192 -192
  60. basilisk/render/image.py +128 -128
  61. basilisk/render/image_handler.py +120 -120
  62. basilisk/render/light.py +96 -96
  63. basilisk/render/light_handler.py +58 -58
  64. basilisk/render/material.py +232 -232
  65. basilisk/render/material_handler.py +133 -133
  66. basilisk/render/post_process.py +180 -180
  67. basilisk/render/shader.py +135 -135
  68. basilisk/render/shader_handler.py +109 -109
  69. basilisk/render/sky.py +119 -119
  70. basilisk/scene.py +295 -291
  71. basilisk/shaders/batch.frag +291 -291
  72. basilisk/shaders/batch.vert +117 -117
  73. basilisk/shaders/bloom_downsample.frag +23 -23
  74. basilisk/shaders/bloom_upsample.frag +33 -33
  75. basilisk/shaders/crt.frag +34 -34
  76. basilisk/shaders/draw.frag +27 -27
  77. basilisk/shaders/draw.vert +25 -25
  78. basilisk/shaders/filter.frag +22 -22
  79. basilisk/shaders/frame.frag +13 -13
  80. basilisk/shaders/frame.vert +13 -13
  81. basilisk/shaders/frame_hdr.frag +27 -27
  82. basilisk/shaders/geometry.frag +10 -10
  83. basilisk/shaders/geometry.vert +41 -41
  84. basilisk/shaders/normal.frag +62 -62
  85. basilisk/shaders/normal.vert +96 -96
  86. basilisk/shaders/particle.frag +81 -81
  87. basilisk/shaders/particle.vert +86 -86
  88. basilisk/shaders/sky.frag +23 -23
  89. basilisk/shaders/sky.vert +13 -13
  90. {basilisk_engine-0.1.51.dist-info → basilisk_engine-0.1.53.dist-info}/METADATA +82 -89
  91. basilisk_engine-0.1.53.dist-info/RECORD +110 -0
  92. {basilisk_engine-0.1.51.dist-info → basilisk_engine-0.1.53.dist-info}/WHEEL +1 -1
  93. basilisk_engine-0.1.51.dist-info/RECORD +0 -110
  94. {basilisk_engine-0.1.51.dist-info → basilisk_engine-0.1.53.dist-info}/top_level.txt +0 -0
basilisk/engine.py CHANGED
@@ -1,169 +1,169 @@
1
- import os
2
- from sys import platform
3
- os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
4
- import pygame as pg
5
- import moderngl as mgl
6
- import glcontext # For packaging (so it isnt a hidden import)
7
- from .render.shader_handler import ShaderHandler
8
- from .render.material_handler import MaterialHandler
9
- from .render.frame import Frame
10
- from .draw.draw_handler import DrawHandler
11
- from .config import Config
12
- from .input_output.mouse import Mouse
13
- from .input_output.clock import Clock
14
- from .input_output.IO_handler import IO
15
- from .mesh.cube import Cube
16
-
17
- class Engine():
18
- win_size: tuple
19
- """Size of the engine window in pixels"""
20
- ctx: mgl.Context
21
- """ModernGL context used by the engine"""
22
- clock: Clock
23
- """Basilisk clock used to keep track of time"""
24
- shader_handler: ShaderHandler=None
25
- """Handler for all shaders used in all scenes of the engine"""
26
- material_handler: MaterialHandler=None
27
- """Handler for all materials and images in all scenes"""
28
- frame: Frame=None
29
- """Default render target for all locations. Rendered to the screen at the end of the frame"""
30
- config: Config
31
- """Object containing all global attributes"""
32
- delta_time: float
33
- """Time in seconds that passed between the last frame"""
34
- time: float
35
- """Total time the engine has been running"""
36
- running: bool=True
37
- """True if the engine is still running"""
38
- mouse: Mouse
39
- """Object containing information about the user's mouse"""
40
- root: str
41
- """Path to the root directory containing internal data"""
42
- current_frame_updated: bool=False
43
- """Flag for if the engine has been updated this frame"""
44
- keys: list[bool]
45
- """List of all keyboard inputs as booleans"""
46
- previous_keys: list[bool]
47
- """List of all keyoard inputs from the last frame as booleans"""
48
-
49
- def __init__(self, win_size=(800, 800), title="Basilisk Engine", vsync=None, max_fps=None, grab_mouse=True, headless=False, resizable=True) -> None:
50
- """
51
- Basilisk Engine Class. Sets up the engine enviornment and allows the user to interact with Basilisk
52
- Args:
53
- win_size: tuple
54
- The initial window size of the engine
55
- title: str
56
- The title of the engine window
57
- vsync: bool
58
- Flag for running engine with vsync enabled
59
- headless: bool
60
- Flag for headless rendering
61
- """
62
-
63
- # Save the window size
64
- self.win_size = win_size
65
-
66
- # Initialize pygame and set OpenGL attributes
67
- pg.init()
68
- pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
69
- pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
70
- pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
71
-
72
- # Platform settings
73
- if platform == 'win32' : self.platform = 'windows'
74
- elif platform == 'darwin': self.platform = 'mac'
75
- else: self.platform = 'linux'
76
- if vsync == None: vsync = True if self.platform == 'linux' else False
77
-
78
- # Initializae the pygame display
79
- self.headless = headless
80
- if headless:
81
- pg.display.set_mode((300, 50), vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
82
- pg.display.iconify()
83
- else:
84
- if resizable: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE)
85
- else: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
86
-
87
- # Initalize pygame sound moduel sound
88
- pg.mixer.pre_init(44100, -16, 2, 512)
89
- pg.mixer.init()
90
- pg.mixer.set_num_channels(64)
91
- pg.mixer.music.set_volume(100/100)
92
-
93
- # MGL context setup
94
- self.ctx = mgl.create_context()
95
- self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
96
-
97
- # Global attributes referenced by the handlers
98
- self.config = Config(self)
99
- self.root = os.path.dirname(__file__)
100
- self.cube = Cube(self)
101
- self.fbos = []
102
-
103
- # Handlers
104
- self.clock = Clock(self, max_fps)
105
- self.IO = IO(self, grab_mouse=grab_mouse, caption=title)
106
- self.material_handler = MaterialHandler(self)
107
- self.shader_handler = ShaderHandler(self)
108
- self.draw_handler = DrawHandler(self)
109
- self.frame = Frame(self)
110
- self.frames = []
111
- self.material_handler.set_base()
112
-
113
- def _update(self) -> None:
114
- """
115
- Internal engine update.
116
- Updates all input, physics, and time variables. Clears the frame.
117
- """
118
-
119
- # Used to lock this internal update until user calls engine.update()
120
- if self.current_frame_updated: return
121
- self.current_frame_updated = True
122
-
123
- # Clear frame data
124
- for fbo in self.fbos: fbo.clear()
125
- self.frames.clear()
126
- self.frame.clear()
127
- self.ctx.clear()
128
-
129
- # Update time and IO
130
- self.clock.update()
131
- self.IO.update()
132
-
133
- def update(self, render=True) -> None:
134
- """
135
- Calls internal update if needed
136
- Renders the draw handler
137
- Renders the engine's frame to the screen.
138
- """
139
-
140
-
141
- # Must update the frame
142
- self._update()
143
- if not self.running: return
144
-
145
- # Clear the screen and render the frame
146
- if render:
147
- # Render all draw calls from the past frame
148
- self.frame.output_buffer.use()
149
- self.draw_handler.render()
150
- self.frame.render(self.ctx.screen)
151
-
152
- # Even though we may not render here, the user might be rendering in their file, so we need to flip
153
- pg.display.flip()
154
-
155
- # Allow for the engine to take in input again
156
- self.current_frame_updated = False
157
-
158
- def quit(self) -> None:
159
- """
160
- Stops the engine and releases all memory
161
- """
162
-
163
- pg.quit()
164
- self.ctx.release()
165
- self.running = False
166
-
167
-
168
- @property
1
+ import os
2
+ from sys import platform
3
+ os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
4
+ import pygame as pg
5
+ import moderngl as mgl
6
+ import glcontext # For packaging (so it isnt a hidden import)
7
+ from .render.shader_handler import ShaderHandler
8
+ from .render.material_handler import MaterialHandler
9
+ from .render.frame import Frame
10
+ from .draw.draw_handler import DrawHandler
11
+ from .config import Config
12
+ from .input_output.mouse import Mouse
13
+ from .input_output.clock import Clock
14
+ from .input_output.IO_handler import IO
15
+ from .mesh.cube import Cube
16
+
17
+ class Engine():
18
+ win_size: tuple
19
+ """Size of the engine window in pixels"""
20
+ ctx: mgl.Context
21
+ """ModernGL context used by the engine"""
22
+ clock: Clock
23
+ """Basilisk clock used to keep track of time"""
24
+ shader_handler: ShaderHandler=None
25
+ """Handler for all shaders used in all scenes of the engine"""
26
+ material_handler: MaterialHandler=None
27
+ """Handler for all materials and images in all scenes"""
28
+ frame: Frame=None
29
+ """Default render target for all locations. Rendered to the screen at the end of the frame"""
30
+ config: Config
31
+ """Object containing all global attributes"""
32
+ delta_time: float
33
+ """Time in seconds that passed between the last frame"""
34
+ time: float
35
+ """Total time the engine has been running"""
36
+ running: bool=True
37
+ """True if the engine is still running"""
38
+ mouse: Mouse
39
+ """Object containing information about the user's mouse"""
40
+ root: str
41
+ """Path to the root directory containing internal data"""
42
+ current_frame_updated: bool=False
43
+ """Flag for if the engine has been updated this frame"""
44
+ keys: list[bool]
45
+ """List of all keyboard inputs as booleans"""
46
+ previous_keys: list[bool]
47
+ """List of all keyoard inputs from the last frame as booleans"""
48
+
49
+ def __init__(self, win_size=(800, 800), title="Basilisk Engine", vsync=None, max_fps=None, grab_mouse=True, headless=False, resizable=True) -> None:
50
+ """
51
+ Basilisk Engine Class. Sets up the engine enviornment and allows the user to interact with Basilisk
52
+ Args:
53
+ win_size: tuple
54
+ The initial window size of the engine
55
+ title: str
56
+ The title of the engine window
57
+ vsync: bool
58
+ Flag for running engine with vsync enabled
59
+ headless: bool
60
+ Flag for headless rendering
61
+ """
62
+
63
+ # Save the window size
64
+ self.win_size = win_size
65
+
66
+ # Initialize pygame and set OpenGL attributes
67
+ pg.init()
68
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
69
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
70
+ pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
71
+
72
+ # Platform settings
73
+ if platform == 'win32' : self.platform = 'windows'
74
+ elif platform == 'darwin': self.platform = 'mac'
75
+ else: self.platform = 'linux'
76
+ if vsync == None: vsync = True if self.platform == 'linux' else False
77
+
78
+ # Initializae the pygame display
79
+ self.headless = headless
80
+ if headless:
81
+ pg.display.set_mode((300, 50), vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
82
+ pg.display.iconify()
83
+ else:
84
+ if resizable: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF | pg.RESIZABLE)
85
+ else: pg.display.set_mode(self.win_size, vsync=vsync, flags=pg.OPENGL | pg.DOUBLEBUF)
86
+
87
+ # Initalize pygame sound moduel sound
88
+ pg.mixer.pre_init(44100, -16, 2, 512)
89
+ pg.mixer.init()
90
+ pg.mixer.set_num_channels(64)
91
+ pg.mixer.music.set_volume(100/100)
92
+
93
+ # MGL context setup
94
+ self.ctx = mgl.create_context()
95
+ self.ctx.enable(flags=mgl.DEPTH_TEST | mgl.CULL_FACE | mgl.BLEND)
96
+
97
+ # Global attributes referenced by the handlers
98
+ self.config = Config(self)
99
+ self.root = os.path.dirname(__file__)
100
+ self.cube = Cube(self)
101
+ self.fbos = []
102
+
103
+ # Handlers
104
+ self.clock = Clock(self, max_fps)
105
+ self.IO = IO(self, grab_mouse=grab_mouse, caption=title)
106
+ self.material_handler = MaterialHandler(self)
107
+ self.shader_handler = ShaderHandler(self)
108
+ self.draw_handler = DrawHandler(self)
109
+ self.frame = Frame(self)
110
+ self.frames = []
111
+ self.material_handler.set_base()
112
+
113
+ def _update(self) -> None:
114
+ """
115
+ Internal engine update.
116
+ Updates all input, physics, and time variables. Clears the frame.
117
+ """
118
+
119
+ # Used to lock this internal update until user calls engine.update()
120
+ if self.current_frame_updated: return
121
+ self.current_frame_updated = True
122
+
123
+ # Clear frame data
124
+ for fbo in self.fbos: fbo.clear()
125
+ self.frames.clear()
126
+ self.frame.clear()
127
+ self.ctx.clear()
128
+
129
+ # Update time and IO
130
+ self.clock.update()
131
+ self.IO.update()
132
+
133
+ def update(self, render=True) -> None:
134
+ """
135
+ Calls internal update if needed
136
+ Renders the draw handler
137
+ Renders the engine's frame to the screen.
138
+ """
139
+
140
+
141
+ # Must update the frame
142
+ self._update()
143
+ if not self.running: return
144
+
145
+ # Clear the screen and render the frame
146
+ if render:
147
+ # Render all draw calls from the past frame
148
+ self.frame.output_buffer.use()
149
+ self.draw_handler.render()
150
+ self.frame.render(self.ctx.screen)
151
+
152
+ # Even though we may not render here, the user might be rendering in their file, so we need to flip
153
+ pg.display.flip()
154
+
155
+ # Allow for the engine to take in input again
156
+ self.current_frame_updated = False
157
+
158
+ def quit(self) -> None:
159
+ """
160
+ Stops the engine and releases all memory
161
+ """
162
+
163
+ pg.quit()
164
+ self.ctx.release()
165
+ self.running = False
166
+
167
+
168
+ @property
169
169
  def shader(self): return self._shader
@@ -1,16 +1,16 @@
1
- import glm
2
-
3
-
4
- class AbstractAABB():
5
- top_right: glm.vec3
6
- """The furthest positive corner of the AABB"""
7
- bottom_left: glm.vec3
8
- """The furthest negative corner of the AABB"""
9
- a: ...
10
- """Binary child 1"""
11
- b: ...
12
- """Binary child 2"""
13
-
14
- class AbstractBVH():
15
- root: AbstractAABB
1
+ import glm
2
+
3
+
4
+ class AbstractAABB():
5
+ top_right: glm.vec3
6
+ """The furthest positive corner of the AABB"""
7
+ bottom_left: glm.vec3
8
+ """The furthest negative corner of the AABB"""
9
+ a: ...
10
+ """Binary child 1"""
11
+ b: ...
12
+ """Binary child 2"""
13
+
14
+ class AbstractBVH():
15
+ root: AbstractAABB
16
16
  """Root aabb used for the start of all collisions"""
@@ -1,134 +1,134 @@
1
- import glm
2
- import numpy as np
3
-
4
-
5
- class Custom():
6
-
7
- def normalize(self):
8
- """
9
- Inplace normalizes the vector
10
- """
11
- self._data = glm.normalize(self._data)
12
- return self
13
-
14
- def apply_function(): ... # will be overridden by child custom classes
15
-
16
- # math functions
17
- def add(self, other):
18
- def func(a, b): return a + b
19
- return self.apply_function(other, func, 'addition')
20
-
21
- def subtract(self, other):
22
- def func(a, b): return a - b
23
- return self.apply_function(other, func, 'subtraction')
24
-
25
- def rhs_subtract(self, other):
26
- def func(a, b): return b - a
27
- return self.apply_function(other, func, 'subtraction')
28
-
29
- def multiply(self, other):
30
- def func(a, b): return a * b
31
- return self.apply_function(other, func, 'multiplication')
32
-
33
- def divide(self, other):
34
- def func(a, b): return a / b
35
- return self.apply_function(other, func, 'division')
36
-
37
- def rhs_divide(self, other):
38
- def func(a, b): return b / a
39
- return self.apply_function(other, func, 'division')
40
-
41
- def floor_divide(self, other):
42
- def func(a, b): return a // b
43
- return self.apply_function(other, func, 'division')
44
-
45
- def rhs_floor_divide(self, other):
46
- def func(a, b): return b // a
47
- return self.apply_function(other, func, 'division')
48
-
49
- def mod(self, other):
50
- def func(a, b): return a % b
51
- return self.apply_function(other, func, 'modulus')
52
-
53
- def rhs_mod(self, other):
54
- def func(a, b): return b % a
55
- return self.apply_function(other, func, 'modulus')
56
-
57
- def pow(self, other):
58
- def func(a, b): return a ** b
59
- return self.apply_function(other, func, 'power')
60
-
61
- def rhs_pow(self, other):
62
- def func(a, b): return b ** a
63
- return self.apply_function(other, func, 'power')
64
-
65
- def __add__(self, other): return self.add(other) # this + that
66
- def __radd__(self, other): return self.add(other) # that + this
67
- def __iadd__(self, other): # this += that
68
- self = self.add(other)
69
- return self
70
-
71
- def __sub__(self, other): return self.subtract(other)
72
- def __rsub__(self, other): return self.rhs_subtract(other) # non-commutative
73
- def __isub__(self, other):
74
- self = self.subtract(other)
75
- return self
76
-
77
- def __mul__(self, other): return self.multiply(other)
78
- def __rmul__(self, other): return self.multiply(other)
79
- def __imul__(self, other):
80
- self = self.multiply(other)
81
- return self
82
-
83
- def __truediv__(self, other): return self.divide(other)
84
- def __rtruediv__(self, other): return self.rhs_divide(other) # non-commutative
85
- def __itruediv__(self, other):
86
- self = self.divide(other)
87
- return self
88
-
89
- def __floordiv__(self, other): return self.floor_divide(other)
90
- def __rfloordiv__(self, other): return self.rhs_floor_divide(other) # non-commutative
91
- def __ifloordiv__(self, other):
92
- self = self.floor_divide(other)
93
- return self
94
-
95
- def __mod__(self, other): return self.mod(other)
96
- def __rmod__(self, other): return self.rhs_mod(other)
97
- def __imod__(self, other):
98
- self = self.mod(other)
99
- return self
100
-
101
- def __pow__(self, other): return self.pow(other)
102
- def __rpow__(self, other): return self.rhs_pow(other)
103
- def __ipow__(self, other):
104
- self = self.pow(other)
105
- return self
106
-
107
- # comparison functions
108
- def __eq__(self, other):
109
- if isinstance(other, Custom): return self.data == other.data
110
- return self.data == other
111
-
112
- def __ne__(self, other):
113
- if isinstance(other, Custom): return self.data != other.data
114
- return self.data != other
115
-
116
- def __lt__(self, other):
117
- if isinstance(other, Custom): return self.data < other.data
118
- return self.data < other
119
-
120
- def __gt__(self, other):
121
- if isinstance(other, Custom): return self.data > other.data
122
- return self.data > other
123
-
124
- def __le__(self, other):
125
- if isinstance(other, Custom): return self.data <= other.data
126
- return self.data <= other
127
-
128
- def __ge__(self, other):
129
- if isinstance(other, Custom): return self.data >= other.data
130
- return self.data >= other
131
-
132
- # unary operators
133
- def __pos__(self):
1
+ import glm
2
+ import numpy as np
3
+
4
+
5
+ class Custom():
6
+
7
+ def normalize(self):
8
+ """
9
+ Inplace normalizes the vector
10
+ """
11
+ self._data = glm.normalize(self._data)
12
+ return self
13
+
14
+ def apply_function(): ... # will be overridden by child custom classes
15
+
16
+ # math functions
17
+ def add(self, other):
18
+ def func(a, b): return a + b
19
+ return self.apply_function(other, func, 'addition')
20
+
21
+ def subtract(self, other):
22
+ def func(a, b): return a - b
23
+ return self.apply_function(other, func, 'subtraction')
24
+
25
+ def rhs_subtract(self, other):
26
+ def func(a, b): return b - a
27
+ return self.apply_function(other, func, 'subtraction')
28
+
29
+ def multiply(self, other):
30
+ def func(a, b): return a * b
31
+ return self.apply_function(other, func, 'multiplication')
32
+
33
+ def divide(self, other):
34
+ def func(a, b): return a / b
35
+ return self.apply_function(other, func, 'division')
36
+
37
+ def rhs_divide(self, other):
38
+ def func(a, b): return b / a
39
+ return self.apply_function(other, func, 'division')
40
+
41
+ def floor_divide(self, other):
42
+ def func(a, b): return a // b
43
+ return self.apply_function(other, func, 'division')
44
+
45
+ def rhs_floor_divide(self, other):
46
+ def func(a, b): return b // a
47
+ return self.apply_function(other, func, 'division')
48
+
49
+ def mod(self, other):
50
+ def func(a, b): return a % b
51
+ return self.apply_function(other, func, 'modulus')
52
+
53
+ def rhs_mod(self, other):
54
+ def func(a, b): return b % a
55
+ return self.apply_function(other, func, 'modulus')
56
+
57
+ def pow(self, other):
58
+ def func(a, b): return a ** b
59
+ return self.apply_function(other, func, 'power')
60
+
61
+ def rhs_pow(self, other):
62
+ def func(a, b): return b ** a
63
+ return self.apply_function(other, func, 'power')
64
+
65
+ def __add__(self, other): return self.add(other) # this + that
66
+ def __radd__(self, other): return self.add(other) # that + this
67
+ def __iadd__(self, other): # this += that
68
+ self = self.add(other)
69
+ return self
70
+
71
+ def __sub__(self, other): return self.subtract(other)
72
+ def __rsub__(self, other): return self.rhs_subtract(other) # non-commutative
73
+ def __isub__(self, other):
74
+ self = self.subtract(other)
75
+ return self
76
+
77
+ def __mul__(self, other): return self.multiply(other)
78
+ def __rmul__(self, other): return self.multiply(other)
79
+ def __imul__(self, other):
80
+ self = self.multiply(other)
81
+ return self
82
+
83
+ def __truediv__(self, other): return self.divide(other)
84
+ def __rtruediv__(self, other): return self.rhs_divide(other) # non-commutative
85
+ def __itruediv__(self, other):
86
+ self = self.divide(other)
87
+ return self
88
+
89
+ def __floordiv__(self, other): return self.floor_divide(other)
90
+ def __rfloordiv__(self, other): return self.rhs_floor_divide(other) # non-commutative
91
+ def __ifloordiv__(self, other):
92
+ self = self.floor_divide(other)
93
+ return self
94
+
95
+ def __mod__(self, other): return self.mod(other)
96
+ def __rmod__(self, other): return self.rhs_mod(other)
97
+ def __imod__(self, other):
98
+ self = self.mod(other)
99
+ return self
100
+
101
+ def __pow__(self, other): return self.pow(other)
102
+ def __rpow__(self, other): return self.rhs_pow(other)
103
+ def __ipow__(self, other):
104
+ self = self.pow(other)
105
+ return self
106
+
107
+ # comparison functions
108
+ def __eq__(self, other):
109
+ if isinstance(other, Custom): return self.data == other.data
110
+ return self.data == other
111
+
112
+ def __ne__(self, other):
113
+ if isinstance(other, Custom): return self.data != other.data
114
+ return self.data != other
115
+
116
+ def __lt__(self, other):
117
+ if isinstance(other, Custom): return self.data < other.data
118
+ return self.data < other
119
+
120
+ def __gt__(self, other):
121
+ if isinstance(other, Custom): return self.data > other.data
122
+ return self.data > other
123
+
124
+ def __le__(self, other):
125
+ if isinstance(other, Custom): return self.data <= other.data
126
+ return self.data <= other
127
+
128
+ def __ge__(self, other):
129
+ if isinstance(other, Custom): return self.data >= other.data
130
+ return self.data >= other
131
+
132
+ # unary operators
133
+ def __pos__(self):
134
134
  return self