picoid 0.0.1__tar.gz

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.
picoid-0.0.1/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, picops
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,4 @@
1
+ include requirements.txt
2
+ include LICENSE
3
+ recursive-include src *.py *.pyx *.pxd *.pyi *.pxi
4
+ recursive-include src *.c *.cpp *.h *.hpp
picoid-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: picoid
3
+ Version: 0.0.1
4
+ Summary: Low Level UUID Implementation for Python
5
+ Author-email: ckirua <aquipongoalgo.dsz@gmail.com>
6
+ License-Expression: BSD-3-Clause
7
+ Requires-Python: >=3.13
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: setuptools>=80.9.0
11
+ Requires-Dist: Cython
12
+ Requires-Dist: picobuild==0.0.5b1
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
15
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
16
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "dev"
17
+ Dynamic: license-file
18
+
19
+ # picoid
20
+ Low Level UUID Implementation for Python
picoid-0.0.1/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # picoid
2
+ Low Level UUID Implementation for Python
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "wheel",
5
+ "Cython",
6
+ "picobuild==0.0.5b1"
7
+ ]
8
+ build-backend = "setuptools.build_meta"
9
+
10
+ [project]
11
+ name = "picoid"
12
+ description = "Low Level UUID Implementation for Python"
13
+ readme = "README.md"
14
+ license = "BSD-3-Clause"
15
+ license-files = ["LICENSE"]
16
+ authors = [{ name = "ckirua", email = "aquipongoalgo.dsz@gmail.com" }]
17
+ requires-python = ">=3.13"
18
+ dynamic = ["version"]
19
+ dependencies = [
20
+ "setuptools>=80.9.0",
21
+ "Cython",
22
+ "picobuild==0.0.5b1",
23
+ ]
24
+
25
+ [project.optional-dependencies]
26
+ dev = ["pytest>=8.0.0", "sphinx>=7.0.0", "sphinx-rtd-theme>=2.0.0"]
27
+
28
+ [tool.setuptools]
29
+ include-package-data = true
30
+
31
+ [tool.setuptools.packages.find]
32
+ where = ["src"]
33
+
34
+ [tool.setuptools.dynamic]
35
+ version = { attr = "picoid.__about__.__version__" }
36
+
37
+ [tool.cibuildwheel]
38
+ enable = ["cpython-freethreading"]
39
+ build = "cp313-* cp314-* cp313t-* cp314t-*"
40
+ build-frontend = "build[uv]"
@@ -0,0 +1,3 @@
1
+ picobuild==0.0.5b1
2
+ pytest
3
+ Cython>=3.0.0
picoid-0.0.1/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
picoid-0.0.1/setup.py ADDED
@@ -0,0 +1,25 @@
1
+ from picobuild import Extension, cythonize, get_cython_build_dir, setup
2
+
3
+ extensions = cythonize(
4
+ Extension(
5
+ "picoid.*",
6
+ ["src/picoid/*.pyx", "src/picoid/uuid.c"],
7
+ extra_compile_args=[
8
+ "-O2",
9
+ "-march=native",
10
+ "-Wno-unused-function",
11
+ "-Wno-unused-variable",
12
+ ],
13
+ language="c",
14
+ ),
15
+ compiler_directives={"language_level": 3},
16
+ build_dir=get_cython_build_dir(),
17
+ )
18
+
19
+
20
+ if __name__ == "__main__":
21
+ setup(
22
+ name="picoid",
23
+ version="0.0.1",
24
+ ext_modules=extensions,
25
+ )
@@ -0,0 +1,3 @@
1
+ """Package version for picoid."""
2
+
3
+ __version__ = "0.0.1"
@@ -0,0 +1,2 @@
1
+ # Cython-only: for other .pyx/.pxd to cimport picoid
2
+ from .picoid cimport UUID, randstr_16, uuid4
@@ -0,0 +1,12 @@
1
+ """
2
+ Low-level UUID implementation for Python.
3
+
4
+ Exposes UUID (compatible with stdlib uuid.UUID), uuid4(), and randstr_16().
5
+ """
6
+
7
+ from typing import Tuple
8
+
9
+ from .__about__ import __version__
10
+ from .picoid import UUID, randstr_16, uuid4
11
+
12
+ __all__: Tuple[str, ...] = ("UUID", "__version__", "randstr_16", "uuid4")
@@ -0,0 +1,47 @@
1
+ /* Copyright (C) 2016-present the asyncpg authors and contributors
2
+ * <see AUTHORS file>
3
+ *
4
+ * This module is part of asyncpg and is released under
5
+ * the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
6
+ */
7
+
8
+ #pragma once
9
+
10
+ #define HEX_PRELUDE const char *__hexm = "0123456789abcdef";
11
+
12
+ #define HEX_1_BYTE(buf, dest) \
13
+ { \
14
+ char byte = (buf)[0]; \
15
+ (dest)[0] = __hexm[(byte >> 4) & 0x0F]; \
16
+ (dest)[1] = __hexm[byte & 0x0F]; \
17
+ }
18
+
19
+ #define HEX_2_BYTES(buf, dest) \
20
+ {HEX_1_BYTE(buf, dest) HEX_1_BYTE(buf + 1, dest + 2)}
21
+
22
+ #define HEX_4_BYTES(buf, dest) \
23
+ {HEX_2_BYTES(buf, dest) HEX_2_BYTES(buf + 2, dest + 4)}
24
+
25
+ #define HEX_8_BYTES(buf, dest) \
26
+ {HEX_4_BYTES(buf, dest) HEX_4_BYTES(buf + 4, dest + 8)}
27
+
28
+ static inline void uuid_to_str(const char *source, char *dest) {
29
+ HEX_PRELUDE
30
+
31
+ HEX_4_BYTES(source, dest)
32
+ dest[8] = '-';
33
+ HEX_2_BYTES(source + 4, dest + 9)
34
+ dest[13] = '-';
35
+ HEX_2_BYTES(source + 6, dest + 14)
36
+ dest[18] = '-';
37
+ HEX_2_BYTES(source + 8, dest + 19)
38
+ dest[23] = '-';
39
+ HEX_4_BYTES(source + 10, dest + 24)
40
+ HEX_2_BYTES(source + 14, dest + 32)
41
+ }
42
+
43
+ static inline void uuid_to_hex(const char *source, char *dest) {
44
+ HEX_PRELUDE
45
+ HEX_8_BYTES(source, dest)
46
+ HEX_8_BYTES(source + 8, dest + 16)
47
+ }
@@ -0,0 +1,38 @@
1
+ # cython: language_level=3
2
+
3
+ cimport cpython
4
+ cimport cython
5
+ from libc.stdint cimport int8_t, uint8_t
6
+ from libc.string cimport memcmp, memcpy
7
+
8
+
9
+ cdef extern from "Python.h":
10
+ int PyUnicode_1BYTE_KIND
11
+ const char* PyUnicode_AsUTF8AndSize(object unicode, Py_ssize_t *size) except NULL
12
+ object PyUnicode_FromKindAndData(int kind, const void *buffer, Py_ssize_t size)
13
+ object PyBytes_FromStringAndSize(const char *s, Py_ssize_t len)
14
+
15
+ cdef extern from "hex.h":
16
+ cdef void uuid_to_str(const char *source, char *dest)
17
+ cdef void uuid_to_hex(const char *source, char *dest)
18
+
19
+ cdef extern from "uuid.h":
20
+ cdef void c_uuid4(unsigned char* dest) nogil
21
+
22
+
23
+ cdef class __UUIDReplaceMe:
24
+ pass
25
+
26
+ @cython.final
27
+ @cython.no_gc_clear
28
+ cdef class UUID(__UUIDReplaceMe):
29
+ cdef char[16] _data
30
+ cdef object _int
31
+ cdef object _hash
32
+
33
+
34
+ cdef UUID uuid_from_buf(const char *buf)
35
+ cdef void uuid_bytes_from_str(str u, char *out)
36
+
37
+ cpdef bytes randstr_16()
38
+ cpdef UUID uuid4()
@@ -0,0 +1,85 @@
1
+ import uuid
2
+ from typing import Any, Tuple, Union
3
+
4
+ class UUID(uuid.UUID):
5
+ """
6
+ UUID type compatible with stdlib uuid.UUID, with fast C-backed storage.
7
+
8
+ Args:
9
+ - inp: A hyphenated UUID string (32 hex chars with optional hyphens)
10
+ or exactly 16 bytes.
11
+
12
+ Returns:
13
+ None (constructor).
14
+ """
15
+
16
+ def __init__(self, inp: Union[str, bytes]) -> None: ...
17
+ @property
18
+ def bytes(self) -> bytes: ...
19
+ @property
20
+ def int(self) -> int: ...
21
+ @property
22
+ def is_safe(self) -> uuid.SafeUUID: ...
23
+ def __str__(self) -> str: ...
24
+ @property
25
+ def hex(self) -> str: ...
26
+ def __repr__(self) -> str: ...
27
+ def __reduce__(self) -> Tuple[type, Tuple[bytes]]: ...
28
+ def __eq__(self, other: Any) -> bool: ...
29
+ def __ne__(self, other: Any) -> bool: ...
30
+ def __lt__(self, other: Any) -> bool: ...
31
+ def __gt__(self, other: Any) -> bool: ...
32
+ def __le__(self, other: Any) -> bool: ...
33
+ def __ge__(self, other: Any) -> bool: ...
34
+ def __hash__(self) -> int: ...
35
+ def __int__(self) -> int: ...
36
+ @property
37
+ def bytes_le(self) -> bytes: ...
38
+ @property
39
+ def fields(self) -> Tuple[int, int, int, int, int, int]: ...
40
+ @property
41
+ def time_low(self) -> int: ...
42
+ @property
43
+ def time_mid(self) -> int: ...
44
+ @property
45
+ def time_hi_version(self) -> int: ...
46
+ @property
47
+ def clock_seq_hi_variant(self) -> int: ...
48
+ @property
49
+ def clock_seq_low(self) -> int: ...
50
+ @property
51
+ def time(self) -> int: ...
52
+ @property
53
+ def clock_seq(self) -> int: ...
54
+ @property
55
+ def node(self) -> int: ...
56
+ @property
57
+ def urn(self) -> str: ...
58
+ @property
59
+ def variant(self) -> uuid.UUID: ...
60
+ @property
61
+ def version(self) -> int: ...
62
+
63
+ def randstr_16() -> bytes:
64
+ """
65
+ Return 16 random bytes with UUID4 version/variant bits set.
66
+
67
+ Args:
68
+ (none)
69
+
70
+ Returns:
71
+ 16 random bytes with UUID4 version/variant bits set (bytes).
72
+ """
73
+ ...
74
+
75
+ def uuid4() -> UUID:
76
+ """
77
+ Generate a random UUID (version 4).
78
+
79
+ Args:
80
+ (none)
81
+
82
+ Returns:
83
+ A new random UUID4 instance (UUID).
84
+ """
85
+ ...
@@ -0,0 +1,377 @@
1
+ # Copyright (C) 2016-present the asyncpg authors and contributors
2
+ # <see AUTHORS file>
3
+ #
4
+ # This module is part of asyncpg and is released under
5
+ # the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ """
8
+ Cython implementation of UUID, uuid4, and randstr_16.
9
+
10
+ Provides a fast UUID type compatible with stdlib uuid.UUID and helpers
11
+ for generating random UUIDs or 16-byte values.
12
+ """
13
+
14
+ import uuid
15
+
16
+ cimport cpython
17
+ cimport cython
18
+ from libc.stdint cimport int8_t, uint8_t
19
+ from libc.string cimport memcmp, memcpy
20
+
21
+
22
+ cdef extern from "Python.h":
23
+ const char* PyUnicode_AsUTF8AndSize(
24
+ object unicode, Py_ssize_t *size) except NULL
25
+ object PyUnicode_FromKindAndData(
26
+ int kind, const void *buffer, Py_ssize_t size)
27
+ object PyBytes_FromStringAndSize(const char *s, Py_ssize_t len)
28
+
29
+ cdef extern from "hex.h":
30
+ cdef void uuid_to_str(const char *source, char *dest)
31
+ cdef void uuid_to_hex(const char *source, char *dest)
32
+
33
+ cdef extern from "uuid.h":
34
+ void c_uuid4(unsigned char* dest) nogil
35
+
36
+
37
+ cdef char[256] _hextable
38
+ _hextable[:] = [
39
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
40
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
41
+ -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
42
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
43
+ -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
44
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
45
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
46
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49
+ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
50
+ ]
51
+
52
+
53
+ cdef std_UUID = uuid.UUID
54
+
55
+
56
+ cdef void uuid_bytes_from_str(str u, char *out):
57
+ cdef:
58
+ const char *orig_buf
59
+ Py_ssize_t size
60
+ unsigned char ch
61
+ uint8_t acc, part, acc_set
62
+ int i, j
63
+
64
+ orig_buf = PyUnicode_AsUTF8AndSize(u, &size)
65
+ if size > 36 or size < 32:
66
+ raise ValueError(
67
+ f'invalid UUID {u!r}: '
68
+ f'length must be between 32..36 characters, got {size}')
69
+
70
+ acc_set = 0
71
+ j = 0
72
+ for i in range(size):
73
+ ch = <unsigned char>orig_buf[i]
74
+ if ch == <unsigned char>b'-':
75
+ continue
76
+
77
+ part = <uint8_t><int8_t>_hextable[ch]
78
+ if part == <uint8_t>-1:
79
+ if ch >= 0x20 and ch <= 0x7e:
80
+ raise ValueError(
81
+ f'invalid UUID {u!r}: unexpected character {chr(ch)!r}')
82
+ else:
83
+ raise ValueError('invalid UUID {u!r}: unexpected character')
84
+
85
+ if acc_set:
86
+ acc |= part
87
+ out[j] = <char>acc
88
+ acc_set = 0
89
+ j += 1
90
+ else:
91
+ acc = <uint8_t>(part << 4)
92
+ acc_set = 1
93
+
94
+ if j > 16 or (j == 16 and acc_set):
95
+ raise ValueError(
96
+ f'invalid UUID {u!r}: decodes to more than 16 bytes')
97
+
98
+ if j != 16:
99
+ raise ValueError(
100
+ f'invalid UUID {u!r}: decodes to less than 16 bytes')
101
+
102
+
103
+ cdef class __UUIDReplaceMe:
104
+ pass
105
+
106
+
107
+ cdef UUID uuid_from_buf(const char *buf):
108
+ cdef:
109
+ UUID u = UUID.__new__(UUID)
110
+ memcpy(u._data, buf, 16)
111
+ return u
112
+
113
+ @cython.final
114
+ @cython.no_gc_clear
115
+ cdef class UUID(__UUIDReplaceMe):
116
+ """
117
+ UUID type compatible with stdlib uuid.UUID, with fast C-backed storage.
118
+
119
+ Args:
120
+ - inp: A hyphenated UUID string (32 hex chars with optional hyphens)
121
+ or exactly 16 bytes.
122
+
123
+ Returns:
124
+ None (constructor).
125
+ """
126
+
127
+ def __cinit__(self):
128
+ self._int = None
129
+ self._hash = None
130
+
131
+ def __init__(self, inp):
132
+ cdef:
133
+ char *buf
134
+ Py_ssize_t size
135
+
136
+ if cpython.PyBytes_Check(inp):
137
+ cpython.PyBytes_AsStringAndSize(inp, &buf, &size)
138
+ if size != 16:
139
+ raise ValueError(f'16 bytes were expected, got {size}')
140
+ memcpy(self._data, buf, 16)
141
+
142
+ elif cpython.PyUnicode_Check(inp):
143
+ uuid_bytes_from_str(inp, self._data)
144
+ else:
145
+ raise TypeError(f'a bytes or str object expected, got {inp!r}')
146
+
147
+ @property
148
+ def bytes(self):
149
+ return cpython.PyBytes_FromStringAndSize(self._data, 16)
150
+
151
+ @property
152
+ def int(self):
153
+ if self._int is None:
154
+ # The cache is important because `self.int` can be
155
+ # used multiple times by __hash__ etc.
156
+ #
157
+ # The or 0 works around a bug interaction between cpython
158
+ # 3.10 and earlier and Cython ~3.0.11 in which
159
+ # int.from_bytes returns a "non-canonical 0" and then
160
+ # # Cython's implementation of & mishandles it.
161
+ # # See cython/cython#6480.
162
+ self._int = int.from_bytes(self.bytes, 'big') or 0
163
+ return self._int
164
+
165
+ @property
166
+ def is_safe(self):
167
+ return uuid.SafeUUID.unknown
168
+
169
+ def __str__(self):
170
+ cdef char[36] out
171
+ uuid_to_str(self._data, out)
172
+ return PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, <void*>out, 36)
173
+
174
+ @property
175
+ def hex(self):
176
+ cdef char[32] out
177
+ uuid_to_hex(self._data, out)
178
+ return PyUnicode_FromKindAndData(PyUnicode_1BYTE_KIND, <void*>out, 32)
179
+
180
+ def __repr__(self):
181
+ return f"UUID('{self}')"
182
+
183
+ def __reduce__(self):
184
+ return (type(self), (self.bytes,))
185
+
186
+ def __eq__(self, other):
187
+ if type(other) is UUID:
188
+ return memcmp(self._data, (<UUID>other)._data, 16) == 0
189
+ if isinstance(other, std_UUID):
190
+ return self.int == other.int
191
+ return NotImplemented
192
+
193
+ def __ne__(self, other):
194
+ if type(other) is UUID:
195
+ return memcmp(self._data, (<UUID>other)._data, 16) != 0
196
+ if isinstance(other, std_UUID):
197
+ return self.int != other.int
198
+ return NotImplemented
199
+
200
+ def __lt__(self, other):
201
+ if type(other) is UUID:
202
+ return memcmp(self._data, (<UUID>other)._data, 16) < 0
203
+ if isinstance(other, std_UUID):
204
+ return self.int < other.int
205
+ return NotImplemented
206
+
207
+ def __gt__(self, other):
208
+ if type(other) is UUID:
209
+ return memcmp(self._data, (<UUID>other)._data, 16) > 0
210
+ if isinstance(other, std_UUID):
211
+ return self.int > other.int
212
+ return NotImplemented
213
+
214
+ def __le__(self, other):
215
+ if type(other) is UUID:
216
+ return memcmp(self._data, (<UUID>other)._data, 16) <= 0
217
+ if isinstance(other, std_UUID):
218
+ return self.int <= other.int
219
+ return NotImplemented
220
+
221
+ def __ge__(self, other):
222
+ if type(other) is UUID:
223
+ return memcmp(self._data, (<UUID>other)._data, 16) >= 0
224
+ if isinstance(other, std_UUID):
225
+ return self.int >= other.int
226
+ return NotImplemented
227
+
228
+ def __hash__(self):
229
+ # In EdgeDB every schema object has a uuid and there are
230
+ # huge hash-maps of them. We want UUID.__hash__ to be
231
+ # as fast as possible.
232
+ if self._hash is not None:
233
+ return self._hash
234
+
235
+ self._hash = hash(self.int)
236
+ return self._hash
237
+
238
+ def __int__(self):
239
+ return self.int
240
+
241
+ @property
242
+ def bytes_le(self):
243
+ bytes = self.bytes
244
+ return (bytes[4-1::-1] + bytes[6-1:4-1:-1] + bytes[8-1:6-1:-1] +
245
+ bytes[8:])
246
+
247
+ @property
248
+ def fields(self):
249
+ return (self.time_low, self.time_mid, self.time_hi_version,
250
+ self.clock_seq_hi_variant, self.clock_seq_low, self.node)
251
+
252
+ @property
253
+ def time_low(self):
254
+ return self.int >> 96
255
+
256
+ @property
257
+ def time_mid(self):
258
+ return (self.int >> 80) & 0xffff
259
+
260
+ @property
261
+ def time_hi_version(self):
262
+ return (self.int >> 64) & 0xffff
263
+
264
+ @property
265
+ def clock_seq_hi_variant(self):
266
+ return (self.int >> 56) & 0xff
267
+
268
+ @property
269
+ def clock_seq_low(self):
270
+ return (self.int >> 48) & 0xff
271
+
272
+ @property
273
+ def time(self):
274
+ return (((self.time_hi_version & 0x0fff) << 48) |
275
+ (self.time_mid << 32) | self.time_low)
276
+
277
+ @property
278
+ def clock_seq(self):
279
+ return (((self.clock_seq_hi_variant & 0x3f) << 8) |
280
+ self.clock_seq_low)
281
+
282
+ @property
283
+ def node(self):
284
+ return self.int & 0xffffffffffff
285
+
286
+ @property
287
+ def urn(self):
288
+ return 'urn:uuid:' + str(self)
289
+
290
+ @property
291
+ def variant(self):
292
+ if not self.int & (0x8000 << 48):
293
+ return uuid.RESERVED_NCS
294
+ elif not self.int & (0x4000 << 48):
295
+ return uuid.RFC_4122
296
+ elif not self.int & (0x2000 << 48):
297
+ return uuid.RESERVED_MICROSOFT
298
+ else:
299
+ return uuid.RESERVED_FUTURE
300
+
301
+ @property
302
+ def version(self):
303
+ # The version bits are only meaningful for RFC 4122 UUIDs.
304
+ if self.variant == uuid.RFC_4122:
305
+ return int((self.int >> 76) & 0xf)
306
+
307
+ # <hack>
308
+ # In order for `isinstance(pgproto.UUID, uuid.UUID)` to work,
309
+ # patch __bases__ and __mro__ by injecting `uuid.UUID`.
310
+ #
311
+ # We apply brute-force here because the following pattern stopped
312
+ # working with Python 3.8:
313
+ #
314
+ # cdef class OurUUID:
315
+ # ...
316
+ #
317
+ # class UUID(OurUUID, uuid.UUID):
318
+ # ...
319
+ #
320
+ # With Python 3.8 it now produces
321
+ #
322
+ # "TypeError: multiple bases have instance lay-out conflict"
323
+ #
324
+ # error. Maybe it's possible to fix this some other way, but
325
+ # the best solution possible would be to just contribute our
326
+ # faster UUID to the standard library and not have this problem
327
+ # at all. For now this hack is pretty safe and should be
328
+ # compatible with future Pythons for long enough.
329
+ #
330
+ assert UUID.__bases__[0] is __UUIDReplaceMe
331
+ assert UUID.__mro__[1] is __UUIDReplaceMe
332
+ cpython.Py_INCREF(std_UUID)
333
+ cpython.PyTuple_SET_ITEM(UUID.__bases__, 0, std_UUID)
334
+ cpython.Py_INCREF(std_UUID)
335
+ cpython.PyTuple_SET_ITEM(UUID.__mro__, 1, std_UUID)
336
+ # </hack>
337
+
338
+
339
+ cdef pg_UUID = UUID
340
+
341
+
342
+
343
+ cpdef bytes randstr_16():
344
+ """
345
+ Return 16 random bytes with UUID4 version/variant bits set.
346
+
347
+ Args:
348
+ (none)
349
+
350
+ Returns:
351
+ 16 random bytes with UUID4 version/variant bits set (bytes).
352
+ """
353
+ cdef:
354
+ unsigned char dest[16]
355
+ bytes result
356
+ with nogil:
357
+ c_uuid4(dest)
358
+ result = PyBytes_FromStringAndSize(<char*>dest, 16)
359
+ return result
360
+
361
+ cpdef UUID uuid4():
362
+ """
363
+ Generate a random UUID (version 4).
364
+
365
+ Args:
366
+ (none)
367
+
368
+ Returns:
369
+ A new random UUID4 instance (UUID).
370
+ """
371
+ cdef:
372
+ unsigned char dest[16]
373
+ UUID result
374
+ with nogil:
375
+ c_uuid4(dest)
376
+ result = uuid_from_buf(<const char *>dest)
377
+ return result
@@ -0,0 +1,69 @@
1
+ #include <stdint.h>
2
+ #include <string.h>
3
+ #include <stdatomic.h>
4
+ #include <stdlib.h>
5
+
6
+ #ifdef _WIN32
7
+ #include <windows.h>
8
+ #include <wincrypt.h>
9
+ static HCRYPTPROV hProvider = 0;
10
+ #else
11
+ #include <fcntl.h>
12
+ #include <unistd.h>
13
+ #include <errno.h>
14
+ static int urandom_fd = -1;
15
+ #endif
16
+
17
+ #define UUID_SIZE 16
18
+ #define BUFFER_SIZE 8192 // 8KB buffer (512 UUIDs)
19
+ static unsigned char random_buffer[BUFFER_SIZE];
20
+ static _Atomic size_t buffer_pos = BUFFER_SIZE; // Start empty to force initial fill
21
+
22
+ static void fill_buffer(void) {
23
+ #ifdef _WIN32
24
+ CryptGenRandom(hProvider, BUFFER_SIZE, random_buffer);
25
+ #else
26
+ if (urandom_fd != -1) {
27
+ ssize_t bytes_read = read(urandom_fd, random_buffer, BUFFER_SIZE);
28
+ if (bytes_read != BUFFER_SIZE) {
29
+ // Handle error - could not read enough random bytes
30
+ exit(1);
31
+ }
32
+ }
33
+ #endif
34
+ buffer_pos = 0;
35
+ }
36
+
37
+ static void __attribute__((constructor)) init_rng(void) {
38
+ #ifdef _WIN32
39
+ CryptAcquireContext(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
40
+ #else
41
+ urandom_fd = open("/dev/urandom", O_RDONLY);
42
+ #endif
43
+ fill_buffer(); // Initial fill
44
+ }
45
+
46
+ static void __attribute__((destructor)) cleanup_rng(void) {
47
+ #ifdef _WIN32
48
+ if (hProvider) CryptReleaseContext(hProvider, 0);
49
+ #else
50
+ if (urandom_fd != -1) close(urandom_fd);
51
+ #endif
52
+ }
53
+
54
+ void c_uuid4(uint8_t uuid[UUID_SIZE]) {
55
+ size_t current_pos = atomic_fetch_add(&buffer_pos, UUID_SIZE);
56
+
57
+ // Check if we need to refill
58
+ if (current_pos + UUID_SIZE > BUFFER_SIZE) {
59
+ fill_buffer();
60
+ current_pos = atomic_fetch_add(&buffer_pos, UUID_SIZE);
61
+ }
62
+
63
+ // Copy bytes from buffer
64
+ memcpy(uuid, random_buffer + current_pos, UUID_SIZE);
65
+
66
+ // Set version and variant
67
+ uuid[6] = (uuid[6] & 0x0F) | 0x40;
68
+ uuid[8] = (uuid[8] & 0x3F) | 0x80;
69
+ }
@@ -0,0 +1,8 @@
1
+ #pragma once
2
+
3
+ #include <stdint.h>
4
+
5
+ #define UUID_SIZE 16
6
+
7
+ // Function to generate a random UUID (version 4)
8
+ void c_uuid4(uint8_t uuid[UUID_SIZE]);
@@ -0,0 +1,16 @@
1
+ cdef extern from "uuid.h":
2
+ cdef void c_uuid4(unsigned char* uuid)
3
+
4
+ ################################################################################
5
+ # Copyright (C) 2016-present the asyncpg authors and contributors
6
+ # <see AUTHORS file>
7
+ #
8
+ # This module is part of asyncpg and is released under
9
+ # the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ cdef extern from "hex.h":
12
+ cdef void uuid_to_str(const char *source, char *dest)
13
+ cdef void uuid_to_hex(const char *source, char *dest)
14
+ # cdef void uuid_to_int(const char *source, unsigned long long *dest)
15
+
16
+ ################################################################################
@@ -0,0 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: picoid
3
+ Version: 0.0.1
4
+ Summary: Low Level UUID Implementation for Python
5
+ Author-email: ckirua <aquipongoalgo.dsz@gmail.com>
6
+ License-Expression: BSD-3-Clause
7
+ Requires-Python: >=3.13
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: setuptools>=80.9.0
11
+ Requires-Dist: Cython
12
+ Requires-Dist: picobuild==0.0.5b1
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
15
+ Requires-Dist: sphinx>=7.0.0; extra == "dev"
16
+ Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "dev"
17
+ Dynamic: license-file
18
+
19
+ # picoid
20
+ Low Level UUID Implementation for Python
@@ -0,0 +1,22 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ requirements.txt
6
+ setup.py
7
+ src/picoid/__about__.py
8
+ src/picoid/__init__.pxd
9
+ src/picoid/__init__.py
10
+ src/picoid/hex.h
11
+ src/picoid/picoid.pxd
12
+ src/picoid/picoid.pyi
13
+ src/picoid/picoid.pyx
14
+ src/picoid/uuid.c
15
+ src/picoid/uuid.h
16
+ src/picoid/uuid.pxd
17
+ src/picoid.egg-info/PKG-INFO
18
+ src/picoid.egg-info/SOURCES.txt
19
+ src/picoid.egg-info/dependency_links.txt
20
+ src/picoid.egg-info/requires.txt
21
+ src/picoid.egg-info/top_level.txt
22
+ tests/test_picoid.py
@@ -0,0 +1,8 @@
1
+ setuptools>=80.9.0
2
+ Cython
3
+ picobuild==0.0.5b1
4
+
5
+ [dev]
6
+ pytest>=8.0.0
7
+ sphinx>=7.0.0
8
+ sphinx-rtd-theme>=2.0.0
@@ -0,0 +1 @@
1
+ picoid
@@ -0,0 +1,31 @@
1
+ """Minimal pytest tests for picoid: every exported name works as expected."""
2
+
3
+ import pytest
4
+
5
+ import picoid
6
+
7
+
8
+ def test_all_exported_names_are_available() -> None:
9
+ """Every name in __all__ is importable from picoid and is usable."""
10
+ assert hasattr(picoid, "__all__")
11
+ assert isinstance(picoid.__all__, tuple)
12
+ assert all(isinstance(name, str) for name in picoid.__all__)
13
+ for name in picoid.__all__:
14
+ assert hasattr(
15
+ picoid, name
16
+ ), f"picoid.__all__ contains {name!r} but picoid has no attribute {name!r}"
17
+
18
+
19
+ def test_version() -> None:
20
+ """__version__ is a non-empty string."""
21
+ assert hasattr(picoid, "__version__")
22
+ v = picoid.__version__
23
+ assert isinstance(v, str)
24
+ assert len(v) > 0
25
+
26
+
27
+ def test_import_from_picoid() -> None:
28
+ """All __all__ names can be imported via 'from picoid import ...'."""
29
+ for name in picoid.__all__:
30
+ module = __import__("picoid", fromlist=[name])
31
+ assert hasattr(module, name), f"from picoid import {name!r} failed"