Add back "set_timezone"

This commit is contained in:
James
2025-12-11 17:44:48 -07:00
parent 3ca3cb3312
commit 74138472b7
122 changed files with 15869 additions and 427 deletions
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,20 @@
Metadata-Version: 2.1
Name: flatbuffers
Version: 25.9.23
Summary: The FlatBuffers serialization format for Python
Home-page: https://google.github.io/flatbuffers/
Author: Derek Bailey
Author-email: derekbailey@google.com
License: Apache 2.0
Project-URL: Documentation, https://google.github.io/flatbuffers/
Project-URL: Source, https://github.com/google/flatbuffers
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
License-File: ../LICENSE
Python runtime library for use with the `Flatbuffers <https://google.github.io/flatbuffers/>`_ serialization format.
@@ -0,0 +1,15 @@
flatbuffers/__init__.py,sha256=vJZrqZOOTKdBNMa_iTKUA6WJG_c_NzKGpFXOe1Igtiw,751
flatbuffers/_version.py,sha256=GVL6M_yJfoAklDfbfTYFV72LDbIU-YgRXL4d1yX3EVw,695
flatbuffers/builder.py,sha256=uusDhSDKpnLLz6KR4vflC7T74VNwQew9QRkRuxGZTDg,25048
flatbuffers/compat.py,sha256=ihBSpWDCSL-vgLSyZtcu8LX3ZI3wz9LhtqItY2GQZgg,2373
flatbuffers/encode.py,sha256=2Or3mgWRAkJiWg-GgYasDU4zIHpQU3W06fmIhwbz5uM,1550
flatbuffers/flexbuffers.py,sha256=yF8Wr4Lo8WJb-pj9NNaIYxLwzlHHyTroM0iO8fyDwbU,44454
flatbuffers/number_types.py,sha256=ijO0QcJiuxlQegoBOed0v9m0DdzTZHWxpTBZUqzsWHA,3762
flatbuffers/packer.py,sha256=LNWym8YgFRqHjcPeGpYY3inCGWH6XnbkQKtAPtFEVas,1164
flatbuffers/table.py,sha256=ciYTmq_CzAuYpb3KAVnl75M84ieChfbyKne-dFHzwwU,4818
flatbuffers/util.py,sha256=mRVQ1VoHp0MJMNtRTUGVzALwN4T_C-U14tMbj99py2A,1608
flatbuffers-25.9.23.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
flatbuffers-25.9.23.dist-info/METADATA,sha256=tTKSAMim3fxiII0atPOplikAqxp8vZwSsKE-vUlqFcE,875
flatbuffers-25.9.23.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
flatbuffers-25.9.23.dist-info/top_level.txt,sha256=UXVWLA8ys6HeqTz6rfKesocUq6ln-ZL8mhZC_cq5BEc,12
flatbuffers-25.9.23.dist-info/RECORD,,
@@ -1,4 +1,6 @@
Wheel-Version: 1.0
Generator: poetry-core 2.2.1
Generator: bdist_wheel (0.45.1)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
@@ -0,0 +1 @@
flatbuffers
+19
View File
@@ -0,0 +1,19 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import util
from ._version import __version__
from .builder import Builder
from .compat import range_func as compat_range
from .table import Table
+17
View File
@@ -0,0 +1,17 @@
# Copyright 2019 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Placeholder, to be updated during the release process
# by the setup.py
__version__ = "25.9.23"
+870
View File
@@ -0,0 +1,870 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import warnings
from . import compat
from . import encode
from . import number_types as N
from . import packer
from .compat import memoryview_type
from .compat import NumpyRequiredForThisFeature, import_numpy
from .compat import range_func
from .number_types import (SOffsetTFlags, UOffsetTFlags, VOffsetTFlags)
np = import_numpy()
## @file
## @addtogroup flatbuffers_python_api
## @{
## @cond FLATBUFFERS_INTERNAL
class OffsetArithmeticError(RuntimeError):
"""Error caused by an Offset arithmetic error.
Probably caused by bad writing of fields. This is considered an unreachable
situation in normal circumstances.
"""
pass
class IsNotNestedError(RuntimeError):
"""Error caused by using a Builder to write Object data when not inside
an Object.
"""
pass
class IsNestedError(RuntimeError):
"""Error caused by using a Builder to begin an Object when an Object is
already being built.
"""
pass
class StructIsNotInlineError(RuntimeError):
"""Error caused by using a Builder to write a Struct at a location that
is not the current Offset.
"""
pass
class BuilderSizeError(RuntimeError):
"""Error caused by causing a Builder to exceed the hardcoded limit of 2
gigabytes.
"""
pass
class BuilderNotFinishedError(RuntimeError):
"""Error caused by not calling `Finish` before calling `Output`."""
pass
class EndVectorLengthMismatched(RuntimeError):
"""The number of elements passed to EndVector does not match the number
specified in StartVector.
"""
pass
# VtableMetadataFields is the count of metadata fields in each vtable.
VtableMetadataFields = 2
## @endcond
class Builder(object):
"""A Builder is used to construct one or more FlatBuffers.
Typically, Builder objects will be used from code generated by the `flatc`
compiler.
A Builder constructs byte buffers in a last-first manner for simplicity and
performance during reading.
Internally, a Builder is a state machine for creating FlatBuffer objects.
It holds the following internal state:
- Bytes: an array of bytes.
- current_vtable: a list of integers.
- vtables: a hash of vtable entries.
Attributes:
Bytes: The internal `bytearray` for the Builder.
finished: A boolean determining if the Builder has been finalized.
"""
## @cond FLATBUFFERS_INTENRAL
__slots__ = (
"Bytes",
"current_vtable",
"head",
"minalign",
"objectEnd",
"vtables",
"nested",
"forceDefaults",
"finished",
"vectorNumElems",
"sharedStrings",
)
"""Maximum buffer size constant, in bytes.
Builder will never allow it's buffer grow over this size.
Currently equals 2Gb.
"""
MAX_BUFFER_SIZE = 2**31
## @endcond
def __init__(self, initialSize=1024):
"""Initializes a Builder of size `initial_size`.
The internal buffer is grown as needed.
"""
if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
raise BuilderSizeError(msg)
self.Bytes = bytearray(initialSize)
## @cond FLATBUFFERS_INTERNAL
self.current_vtable = None
self.head = UOffsetTFlags.py_type(initialSize)
self.minalign = 1
self.objectEnd = None
self.vtables = {}
self.nested = False
self.forceDefaults = False
self.sharedStrings = {}
## @endcond
self.finished = False
def Clear(self) -> None:
## @cond FLATBUFFERS_INTERNAL
self.current_vtable = None
self.head = UOffsetTFlags.py_type(len(self.Bytes))
self.minalign = 1
self.objectEnd = None
self.vtables = {}
self.nested = False
self.forceDefaults = False
self.sharedStrings = {}
self.vectorNumElems = None
## @endcond
self.finished = False
def Output(self):
"""Return the portion of the buffer that has been used for writing data.
This is the typical way to access the FlatBuffer data inside the
builder. If you try to access `Builder.Bytes` directly, you would need
to manually index it with `Head()`, since the buffer is constructed
backwards.
It raises BuilderNotFinishedError if the buffer has not been finished
with `Finish`.
"""
if not self.finished:
raise BuilderNotFinishedError()
return self.Bytes[self.Head() :]
## @cond FLATBUFFERS_INTERNAL
def StartObject(self, numfields):
"""StartObject initializes bookkeeping for writing a new object."""
self.assertNotNested()
# use 32-bit offsets so that arithmetic doesn't overflow.
self.current_vtable = [0 for _ in range_func(numfields)]
self.objectEnd = self.Offset()
self.nested = True
def WriteVtable(self):
"""WriteVtable serializes the vtable for the current object, if needed.
Before writing out the vtable, this checks pre-existing vtables for
equality to this one. If an equal vtable is found, point the object to
the existing vtable and return.
Because vtable values are sensitive to alignment of object data, not
all logically-equal vtables will be deduplicated.
A vtable has the following format:
<VOffsetT: size of the vtable in bytes, including this value>
<VOffsetT: size of the object in bytes, including the vtable offset>
<VOffsetT: offset for a field> * N, where N is the number of fields
in the schema for this type. Includes deprecated fields.
Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
An object has the following format:
<SOffsetT: offset to this object's vtable (may be negative)>
<byte: data>+
"""
# Prepend a zero scalar to the object. Later in this function we'll
# write an offset here that points to the object's vtable:
self.PrependSOffsetTRelative(0)
objectOffset = self.Offset()
vtKey = []
trim = True
for elem in reversed(self.current_vtable):
if elem == 0:
if trim:
continue
else:
elem = objectOffset - elem
trim = False
vtKey.append(elem)
vtKey = tuple(vtKey)
vt2Offset = self.vtables.get(vtKey)
if vt2Offset is None:
# Did not find a vtable, so write this one to the buffer.
# Write out the current vtable in reverse , because
# serialization occurs in last-first order:
i = len(self.current_vtable) - 1
trailing = 0
trim = True
while i >= 0:
off = 0
elem = self.current_vtable[i]
i -= 1
if elem == 0:
if trim:
trailing += 1
continue
else:
# Forward reference to field;
# use 32bit number to ensure no overflow:
off = objectOffset - elem
trim = False
self.PrependVOffsetT(off)
# The two metadata fields are written last.
# First, store the object bytesize:
objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
# Second, store the vtable bytesize:
vBytes = len(self.current_vtable) - trailing + VtableMetadataFields
vBytes *= N.VOffsetTFlags.bytewidth
self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
# Next, write the offset to the new vtable in the
# already-allocated SOffsetT at the beginning of this object:
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
encode.Write(
packer.soffset,
self.Bytes,
objectStart,
SOffsetTFlags.py_type(self.Offset() - objectOffset),
)
# Finally, store this vtable in memory for future
# deduplication:
self.vtables[vtKey] = self.Offset()
else:
# Found a duplicate vtable.
objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
self.head = UOffsetTFlags.py_type(objectStart)
# Write the offset to the found vtable in the
# already-allocated SOffsetT at the beginning of this object:
encode.Write(
packer.soffset,
self.Bytes,
self.Head(),
SOffsetTFlags.py_type(vt2Offset - objectOffset),
)
self.current_vtable = None
return objectOffset
def EndObject(self):
"""EndObject writes data necessary to finish object construction."""
self.assertNested()
self.nested = False
return self.WriteVtable()
def growByteBuffer(self):
"""Doubles the size of the byteslice, and copies the old data towards
the end of the new buffer (since we build the buffer backwards).
"""
if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
raise BuilderSizeError(msg)
newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
if newSize == 0:
newSize = 1
bytes2 = bytearray(newSize)
bytes2[newSize - len(self.Bytes) :] = self.Bytes
self.Bytes = bytes2
## @endcond
def Head(self):
"""Get the start of useful data in the underlying byte buffer.
Note: unlike other functions, this value is interpreted as from the
left.
"""
## @cond FLATBUFFERS_INTERNAL
return self.head
## @endcond
## @cond FLATBUFFERS_INTERNAL
def Offset(self):
"""Offset relative to the end of the buffer."""
return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
def Pad(self, n):
"""Pad places zeros at the current offset."""
for i in range_func(n):
self.Place(0, N.Uint8Flags)
def Prep(self, size, additionalBytes):
"""Prep prepares to write an element of `size` after `additional_bytes`
have been written, e.g. if you write a string, you need to align
such the int length field is aligned to SizeInt32, and the string
data follows it directly.
If all you need to do is align, `additionalBytes` will be 0.
"""
# Track the biggest thing we've ever aligned to.
if size > self.minalign:
self.minalign = size
# Find the amount of alignment needed such that `size` is properly
# aligned after `additionalBytes`:
alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
alignSize &= size - 1
# Reallocate the buffer if needed:
while self.Head() < alignSize + size + additionalBytes:
oldBufSize = len(self.Bytes)
self.growByteBuffer()
updated_head = self.head + len(self.Bytes) - oldBufSize
self.head = UOffsetTFlags.py_type(updated_head)
self.Pad(alignSize)
def PrependSOffsetTRelative(self, off):
"""PrependSOffsetTRelative prepends an SOffsetT, relative to where it
will be written.
"""
# Ensure alignment is already done:
self.Prep(N.SOffsetTFlags.bytewidth, 0)
if not (off <= self.Offset()):
msg = "flatbuffers: Offset arithmetic error."
raise OffsetArithmeticError(msg)
off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
self.PlaceSOffsetT(off2)
## @endcond
def PrependUOffsetTRelative(self, off):
"""Prepends an unsigned offset into vector data, relative to where it
will be written.
"""
# Ensure alignment is already done:
self.Prep(N.UOffsetTFlags.bytewidth, 0)
if not (off <= self.Offset()):
msg = "flatbuffers: Offset arithmetic error."
raise OffsetArithmeticError(msg)
off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
self.PlaceUOffsetT(off2)
## @cond FLATBUFFERS_INTERNAL
def StartVector(self, elemSize, numElems, alignment):
"""StartVector initializes bookkeeping for writing a new vector.
A vector has the following format:
- <UOffsetT: number of elements in this vector>
- <T: data>+, where T is the type of elements of this vector.
"""
self.assertNotNested()
self.nested = True
self.vectorNumElems = numElems
self.Prep(N.Uint32Flags.bytewidth, elemSize * numElems)
self.Prep(alignment, elemSize * numElems) # In case alignment > int.
return self.Offset()
## @endcond
def EndVector(self, numElems=None):
"""EndVector writes data necessary to finish vector construction."""
self.assertNested()
## @cond FLATBUFFERS_INTERNAL
self.nested = False
## @endcond
if numElems:
warnings.warn("numElems is deprecated.", DeprecationWarning, stacklevel=2)
if numElems != self.vectorNumElems:
raise EndVectorLengthMismatched()
# we already made space for this, so write without PrependUint32
self.PlaceUOffsetT(self.vectorNumElems)
self.vectorNumElems = None
return self.Offset()
def CreateSharedString(self, s, encoding="utf-8", errors="strict"):
"""CreateSharedString checks if the string is already written to the buffer
before calling CreateString.
"""
if s in self.sharedStrings:
return self.sharedStrings[s]
off = self.CreateString(s, encoding, errors)
self.sharedStrings[s] = off
return off
def CreateString(self, s, encoding="utf-8", errors="strict"):
"""CreateString writes a null-terminated byte string as a vector."""
self.assertNotNested()
## @cond FLATBUFFERS_INTERNAL
self.nested = True
## @endcond
if isinstance(s, compat.string_types):
x = s.encode(encoding, errors)
elif isinstance(s, compat.binary_types):
x = s
else:
raise TypeError("non-string passed to CreateString")
self.Prep(N.UOffsetTFlags.bytewidth, (len(x) + 1) * N.Uint8Flags.bytewidth)
self.Place(0, N.Uint8Flags)
l = UOffsetTFlags.py_type(len(s))
## @cond FLATBUFFERS_INTERNAL
self.head = UOffsetTFlags.py_type(self.Head() - l)
## @endcond
self.Bytes[self.Head() : self.Head() + l] = x
self.vectorNumElems = len(x)
return self.EndVector()
def CreateByteVector(self, x):
"""CreateString writes a byte vector."""
self.assertNotNested()
## @cond FLATBUFFERS_INTERNAL
self.nested = True
## @endcond
if not isinstance(x, compat.binary_types):
raise TypeError("non-byte vector passed to CreateByteVector")
self.Prep(N.UOffsetTFlags.bytewidth, len(x) * N.Uint8Flags.bytewidth)
l = UOffsetTFlags.py_type(len(x))
## @cond FLATBUFFERS_INTERNAL
self.head = UOffsetTFlags.py_type(self.Head() - l)
## @endcond
self.Bytes[self.Head() : self.Head() + l] = x
self.vectorNumElems = len(x)
return self.EndVector()
def CreateNumpyVector(self, x):
"""CreateNumpyVector writes a numpy array into the buffer."""
if np is None:
# Numpy is required for this feature
raise NumpyRequiredForThisFeature("Numpy was not found.")
if not isinstance(x, np.ndarray):
raise TypeError("non-numpy-ndarray passed to CreateNumpyVector")
if x.dtype.kind not in ["b", "i", "u", "f"]:
raise TypeError("numpy-ndarray holds elements of unsupported datatype")
if x.ndim > 1:
raise TypeError("multidimensional-ndarray passed to CreateNumpyVector")
self.StartVector(x.itemsize, x.size, x.dtype.alignment)
# Ensure little endian byte ordering
if x.dtype.str[0] == "<":
x_lend = x
else:
x_lend = x.byteswap(inplace=False)
# Calculate total length
l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size)
## @cond FLATBUFFERS_INTERNAL
self.head = UOffsetTFlags.py_type(self.Head() - l)
## @endcond
# tobytes ensures c_contiguous ordering
self.Bytes[self.Head() : self.Head() + l] = x_lend.tobytes(order="C")
self.vectorNumElems = x.size
return self.EndVector()
## @cond FLATBUFFERS_INTERNAL
def assertNested(self):
"""Check that we are in the process of building an object."""
if not self.nested:
raise IsNotNestedError()
def assertNotNested(self):
"""Check that no other objects are being built while making this object.
If not, raise an exception.
"""
if self.nested:
raise IsNestedError()
def assertStructIsInline(self, obj):
"""Structs are always stored inline, so need to be created right
where they are used. You'll get this error if you created it
elsewhere.
"""
N.enforce_number(obj, N.UOffsetTFlags)
if obj != self.Offset():
msg = (
"flatbuffers: Tried to write a Struct at an Offset that "
"is different from the current Offset of the Builder."
)
raise StructIsNotInlineError(msg)
def Slot(self, slotnum):
"""Slot sets the vtable key `voffset` to the current location in the
buffer.
"""
self.assertNested()
self.current_vtable[slotnum] = self.Offset()
## @endcond
def __Finish(self, rootTable, sizePrefix, file_identifier=None):
"""Finish finalizes a buffer, pointing to the given `rootTable`."""
N.enforce_number(rootTable, N.UOffsetTFlags)
prepSize = N.UOffsetTFlags.bytewidth
if file_identifier is not None:
prepSize += N.Int32Flags.bytewidth
if sizePrefix:
prepSize += N.Int32Flags.bytewidth
self.Prep(self.minalign, prepSize)
if file_identifier is not None:
self.Prep(N.UOffsetTFlags.bytewidth, encode.FILE_IDENTIFIER_LENGTH)
# Convert bytes object file_identifier to an array of 4 8-bit integers,
# and use big-endian to enforce size compliance.
# https://docs.python.org/2/library/struct.html#format-characters
file_identifier = N.struct.unpack(">BBBB", file_identifier)
for i in range(encode.FILE_IDENTIFIER_LENGTH - 1, -1, -1):
# Place the bytes of the file_identifer in reverse order:
self.Place(file_identifier[i], N.Uint8Flags)
self.PrependUOffsetTRelative(rootTable)
if sizePrefix:
size = len(self.Bytes) - self.Head()
N.enforce_number(size, N.Int32Flags)
self.PrependInt32(size)
self.finished = True
return self.Head()
def Finish(self, rootTable, file_identifier=None):
"""Finish finalizes a buffer, pointing to the given `rootTable`."""
return self.__Finish(rootTable, False, file_identifier=file_identifier)
def FinishSizePrefixed(self, rootTable, file_identifier=None):
"""Finish finalizes a buffer, pointing to the given `rootTable`,
with the size prefixed.
"""
return self.__Finish(rootTable, True, file_identifier=file_identifier)
## @cond FLATBUFFERS_INTERNAL
def Prepend(self, flags, off):
self.Prep(flags.bytewidth, 0)
self.Place(off, flags)
def PrependSlot(self, flags, o, x, d):
if x is not None:
N.enforce_number(x, flags)
if d is not None:
N.enforce_number(d, flags)
if x != d or (self.forceDefaults and d is not None):
self.Prepend(flags, x)
self.Slot(o)
def PrependBoolSlot(self, *args):
self.PrependSlot(N.BoolFlags, *args)
def PrependByteSlot(self, *args):
self.PrependSlot(N.Uint8Flags, *args)
def PrependUint8Slot(self, *args):
self.PrependSlot(N.Uint8Flags, *args)
def PrependUint16Slot(self, *args):
self.PrependSlot(N.Uint16Flags, *args)
def PrependUint32Slot(self, *args):
self.PrependSlot(N.Uint32Flags, *args)
def PrependUint64Slot(self, *args):
self.PrependSlot(N.Uint64Flags, *args)
def PrependInt8Slot(self, *args):
self.PrependSlot(N.Int8Flags, *args)
def PrependInt16Slot(self, *args):
self.PrependSlot(N.Int16Flags, *args)
def PrependInt32Slot(self, *args):
self.PrependSlot(N.Int32Flags, *args)
def PrependInt64Slot(self, *args):
self.PrependSlot(N.Int64Flags, *args)
def PrependFloat32Slot(self, *args):
self.PrependSlot(N.Float32Flags, *args)
def PrependFloat64Slot(self, *args):
self.PrependSlot(N.Float64Flags, *args)
def PrependUOffsetTRelativeSlot(self, o, x, d):
"""PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
vtable slot `o`. If value `x` equals default `d`, then the slot will
be set to zero and no other data will be written.
"""
if x != d or self.forceDefaults:
self.PrependUOffsetTRelative(x)
self.Slot(o)
def PrependStructSlot(self, v, x, d):
"""PrependStructSlot prepends a struct onto the object at vtable slot `o`.
Structs are stored inline, so nothing additional is being added. In
generated code, `d` is always 0.
"""
N.enforce_number(d, N.UOffsetTFlags)
if x != d:
self.assertStructIsInline(x)
self.Slot(v)
## @endcond
def PrependBool(self, x):
"""Prepend a `bool` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.BoolFlags, x)
def PrependByte(self, x):
"""Prepend a `byte` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Uint8Flags, x)
def PrependUint8(self, x):
"""Prepend an `uint8` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Uint8Flags, x)
def PrependUint16(self, x):
"""Prepend an `uint16` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Uint16Flags, x)
def PrependUint32(self, x):
"""Prepend an `uint32` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Uint32Flags, x)
def PrependUint64(self, x):
"""Prepend an `uint64` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Uint64Flags, x)
def PrependInt8(self, x):
"""Prepend an `int8` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Int8Flags, x)
def PrependInt16(self, x):
"""Prepend an `int16` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Int16Flags, x)
def PrependInt32(self, x):
"""Prepend an `int32` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Int32Flags, x)
def PrependInt64(self, x):
"""Prepend an `int64` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Int64Flags, x)
def PrependFloat32(self, x):
"""Prepend a `float32` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Float32Flags, x)
def PrependFloat64(self, x):
"""Prepend a `float64` to the Builder buffer.
Note: aligns and checks for space.
"""
self.Prepend(N.Float64Flags, x)
def ForceDefaults(self, forceDefaults):
"""In order to save space, fields that are set to their default value
don't get serialized into the buffer. Forcing defaults provides a
way to manually disable this optimization. When set to `True`, will
always serialize default values.
"""
self.forceDefaults = forceDefaults
##############################################################
## @cond FLATBUFFERS_INTERNAL
def PrependVOffsetT(self, x):
self.Prepend(N.VOffsetTFlags, x)
def Place(self, x, flags):
"""Place prepends a value specified by `flags` to the Builder,
without checking for available space.
"""
N.enforce_number(x, flags)
self.head = self.head - flags.bytewidth
encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
def PlaceVOffsetT(self, x):
"""PlaceVOffsetT prepends a VOffsetT to the Builder, without checking
for space.
"""
N.enforce_number(x, N.VOffsetTFlags)
self.head = self.head - N.VOffsetTFlags.bytewidth
encode.Write(packer.voffset, self.Bytes, self.Head(), x)
def PlaceSOffsetT(self, x):
"""PlaceSOffsetT prepends a SOffsetT to the Builder, without checking
for space.
"""
N.enforce_number(x, N.SOffsetTFlags)
self.head = self.head - N.SOffsetTFlags.bytewidth
encode.Write(packer.soffset, self.Bytes, self.Head(), x)
def PlaceUOffsetT(self, x):
"""PlaceUOffsetT prepends a UOffsetT to the Builder, without checking
for space.
"""
N.enforce_number(x, N.UOffsetTFlags)
self.head = self.head - N.UOffsetTFlags.bytewidth
encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
## @endcond
## @cond FLATBUFFERS_INTERNAL
def vtableEqual(a, objectStart, b):
"""vtableEqual compares an unwritten vtable to a written vtable."""
N.enforce_number(objectStart, N.UOffsetTFlags)
if len(a) * N.VOffsetTFlags.bytewidth != len(b):
return False
for i, elem in enumerate(a):
x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
# Skip vtable entries that indicate a default value.
if x == 0 and elem == 0:
pass
else:
y = objectStart - elem
if x != y:
return False
return True
## @endcond
## @}
+91
View File
@@ -0,0 +1,91 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A tiny version of `six` to help with backwards compability.
Also includes compatibility helpers for numpy.
"""
import sys
PY2 = sys.version_info[0] == 2
PY26 = sys.version_info[0:2] == (2, 6)
PY27 = sys.version_info[0:2] == (2, 7)
PY275 = sys.version_info[0:3] >= (2, 7, 5)
PY3 = sys.version_info[0] == 3
PY34 = sys.version_info[0:2] >= (3, 4)
if PY3:
import importlib.machinery
string_types = (str,)
binary_types = (bytes, bytearray)
range_func = range
memoryview_type = memoryview
struct_bool_decl = "?"
else:
import imp
string_types = (unicode,)
if PY26 or PY27:
binary_types = (str, bytearray)
else:
binary_types = (str,)
range_func = xrange
if PY26 or (PY27 and not PY275):
memoryview_type = buffer
struct_bool_decl = "<b"
else:
memoryview_type = memoryview
struct_bool_decl = "?"
# Helper functions to facilitate making numpy optional instead of required
def import_numpy():
"""Returns the numpy module if it exists on the system,
otherwise returns None.
"""
if PY3:
numpy_exists = importlib.machinery.PathFinder.find_spec("numpy") is not None
else:
try:
imp.find_module("numpy")
numpy_exists = True
except ImportError:
numpy_exists = False
if numpy_exists:
# We do this outside of try/except block in case numpy exists
# but is not installed correctly. We do not want to catch an
# incorrect installation which would manifest as an
# ImportError.
import numpy as np
else:
np = None
return np
class NumpyRequiredForThisFeature(RuntimeError):
"""Error raised when user tries to use a feature that
requires numpy without having numpy installed.
"""
pass
# NOTE: Future Jython support may require code here (look at `six`).
+45
View File
@@ -0,0 +1,45 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import number_types as N
from . import packer
from .compat import memoryview_type
from .compat import NumpyRequiredForThisFeature, import_numpy
np = import_numpy()
FILE_IDENTIFIER_LENGTH = 4
def Get(packer_type, buf, head):
"""Get decodes a value at buf[head] using `packer_type`."""
return packer_type.unpack_from(memoryview_type(buf), head)[0]
def GetVectorAsNumpy(numpy_type, buf, count, offset):
"""GetVecAsNumpy decodes values starting at buf[head] as
`numpy_type`, where `numpy_type` is a numpy dtype.
"""
if np is not None:
# TODO: could set .flags.writeable = False to make users jump through
# hoops before modifying...
return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
else:
raise NumpyRequiredForThisFeature('Numpy was not found.')
def Write(packer_type, buf, head, n):
"""Write encodes `n` at buf[head] using `packer_type`."""
packer_type.pack_into(buf, head, n)
File diff suppressed because it is too large Load Diff
+182
View File
@@ -0,0 +1,182 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import collections
import struct
from . import packer
from .compat import NumpyRequiredForThisFeature, import_numpy
np = import_numpy()
# For reference, see:
# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
# These classes could be collections.namedtuple instances, but those are new
# in 2.6 and we want to work towards 2.5 compatability.
class BoolFlags(object):
bytewidth = 1
min_val = False
max_val = True
py_type = bool
name = "bool"
packer_type = packer.boolean
class Uint8Flags(object):
bytewidth = 1
min_val = 0
max_val = (2**8) - 1
py_type = int
name = "uint8"
packer_type = packer.uint8
class Uint16Flags(object):
bytewidth = 2
min_val = 0
max_val = (2**16) - 1
py_type = int
name = "uint16"
packer_type = packer.uint16
class Uint32Flags(object):
bytewidth = 4
min_val = 0
max_val = (2**32) - 1
py_type = int
name = "uint32"
packer_type = packer.uint32
class Uint64Flags(object):
bytewidth = 8
min_val = 0
max_val = (2**64) - 1
py_type = int
name = "uint64"
packer_type = packer.uint64
class Int8Flags(object):
bytewidth = 1
min_val = -(2**7)
max_val = (2**7) - 1
py_type = int
name = "int8"
packer_type = packer.int8
class Int16Flags(object):
bytewidth = 2
min_val = -(2**15)
max_val = (2**15) - 1
py_type = int
name = "int16"
packer_type = packer.int16
class Int32Flags(object):
bytewidth = 4
min_val = -(2**31)
max_val = (2**31) - 1
py_type = int
name = "int32"
packer_type = packer.int32
class Int64Flags(object):
bytewidth = 8
min_val = -(2**63)
max_val = (2**63) - 1
py_type = int
name = "int64"
packer_type = packer.int64
class Float32Flags(object):
bytewidth = 4
min_val = None
max_val = None
py_type = float
name = "float32"
packer_type = packer.float32
class Float64Flags(object):
bytewidth = 8
min_val = None
max_val = None
py_type = float
name = "float64"
packer_type = packer.float64
class SOffsetTFlags(Int32Flags):
pass
class UOffsetTFlags(Uint32Flags):
pass
class VOffsetTFlags(Uint16Flags):
pass
def valid_number(n, flags):
if flags.min_val is None and flags.max_val is None:
return True
return flags.min_val <= n <= flags.max_val
def enforce_number(n, flags):
if flags.min_val is None and flags.max_val is None:
return
if not flags.min_val <= n <= flags.max_val:
raise TypeError("bad number %s for type %s" % (str(n), flags.name))
def float32_to_uint32(n):
packed = struct.pack("<1f", n)
(converted,) = struct.unpack("<1L", packed)
return converted
def uint32_to_float32(n):
packed = struct.pack("<1L", n)
(unpacked,) = struct.unpack("<1f", packed)
return unpacked
def float64_to_uint64(n):
packed = struct.pack("<1d", n)
(converted,) = struct.unpack("<1Q", packed)
return converted
def uint64_to_float64(n):
packed = struct.pack("<1Q", n)
(unpacked,) = struct.unpack("<1d", packed)
return unpacked
def to_numpy_type(number_type):
if np is not None:
return np.dtype(number_type.name).newbyteorder("<")
else:
raise NumpyRequiredForThisFeature("Numpy was not found.")
+41
View File
@@ -0,0 +1,41 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Provide pre-compiled struct packers for encoding and decoding.
See: https://docs.python.org/2/library/struct.html#format-characters
"""
import struct
from . import compat
boolean = struct.Struct(compat.struct_bool_decl)
uint8 = struct.Struct("<B")
uint16 = struct.Struct("<H")
uint32 = struct.Struct("<I")
uint64 = struct.Struct("<Q")
int8 = struct.Struct("<b")
int16 = struct.Struct("<h")
int32 = struct.Struct("<i")
int64 = struct.Struct("<q")
float32 = struct.Struct("<f")
float64 = struct.Struct("<d")
uoffset = uint32
soffset = int32
voffset = uint16
+148
View File
@@ -0,0 +1,148 @@
# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import encode
from . import number_types as N
class Table(object):
"""Table wraps a byte slice and provides read access to its data.
The variable `Pos` indicates the root of the FlatBuffers object therein.
"""
__slots__ = ("Bytes", "Pos")
def __init__(self, buf, pos):
N.enforce_number(pos, N.UOffsetTFlags)
self.Bytes = buf
self.Pos = pos
def Offset(self, vtableOffset):
"""Offset provides access into the Table's vtable.
Deprecated fields are ignored by checking the vtable's length.
"""
vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos)
vtableEnd = self.Get(N.VOffsetTFlags, vtable)
if vtableOffset < vtableEnd:
return self.Get(N.VOffsetTFlags, vtable + vtableOffset)
return 0
def Indirect(self, off):
"""Indirect retrieves the relative offset stored at `offset`."""
N.enforce_number(off, N.UOffsetTFlags)
return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
def String(self, off):
"""String gets a string from data stored inside the flatbuffer."""
N.enforce_number(off, N.UOffsetTFlags)
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
start = off + N.UOffsetTFlags.bytewidth
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
return bytes(self.Bytes[start : start + length])
def VectorLen(self, off):
"""VectorLen retrieves the length of the vector whose offset is stored
at "off" in this object.
"""
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
return ret
def Vector(self, off):
"""Vector retrieves the start of data of the vector whose offset is
stored at "off" in this object.
"""
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
x = off + self.Get(N.UOffsetTFlags, off)
# data starts after metadata containing the vector length
x += N.UOffsetTFlags.bytewidth
return x
def Union(self, t2, off):
"""Union initializes any Table-derived type to point to the union at
the given offset.
"""
assert type(t2) is Table
N.enforce_number(off, N.UOffsetTFlags)
off += self.Pos
t2.Pos = off + self.Get(N.UOffsetTFlags, off)
t2.Bytes = self.Bytes
def Get(self, flags, off):
"""Get retrieves a value of the type specified by `flags` at the
given offset.
"""
N.enforce_number(off, N.UOffsetTFlags)
return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off))
def GetSlot(self, slot, d, validator_flags):
N.enforce_number(slot, N.VOffsetTFlags)
if validator_flags is not None:
N.enforce_number(d, validator_flags)
off = self.Offset(slot)
if off == 0:
return d
return self.Get(validator_flags, self.Pos + off)
def GetVectorAsNumpy(self, flags, off):
"""GetVectorAsNumpy returns the vector that starts at `Vector(off)`
as a numpy array with the type specified by `flags`. The array is
a `view` into Bytes, so modifying the returned array will
modify Bytes in place.
"""
offset = self.Vector(off)
length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
numpy_dtype = N.to_numpy_type(flags)
return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
def GetArrayAsNumpy(self, flags, off, length):
"""GetArrayAsNumpy returns the array with fixed width that starts at `Vector(offset)`
with length `length` as a numpy array with the type specified by `flags`.
The
array is a `view` into Bytes so modifying the returned will modify Bytes in
place.
"""
numpy_dtype = N.to_numpy_type(flags)
return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, off)
def GetVOffsetTSlot(self, slot, d):
"""GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
points to. If the vtable value is zero, the default value `d`
will be returned.
"""
N.enforce_number(slot, N.VOffsetTFlags)
N.enforce_number(d, N.VOffsetTFlags)
off = self.Offset(slot)
if off == 0:
return d
return off
+47
View File
@@ -0,0 +1,47 @@
# Copyright 2017 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import encode
from . import number_types
from . import packer
def GetSizePrefix(buf, offset):
"""Extract the size prefix from a buffer."""
return encode.Get(packer.int32, buf, offset)
def GetBufferIdentifier(buf, offset, size_prefixed=False):
"""Extract the file_identifier from a buffer"""
if size_prefixed:
# increase offset by size of UOffsetTFlags
offset += number_types.UOffsetTFlags.bytewidth
# increase offset by size of root table pointer
offset += number_types.UOffsetTFlags.bytewidth
# end of FILE_IDENTIFIER
end = offset + encode.FILE_IDENTIFIER_LENGTH
return buf[offset:end]
def BufferHasIdentifier(buf, offset, file_identifier, size_prefixed=False):
got = GetBufferIdentifier(buf, offset, size_prefixed=size_prefixed)
return got == file_identifier
def RemoveSizePrefix(buf, offset):
"""Create a slice of a size-prefixed buffer that has
its position advanced just past the size prefix.
"""
return buf, offset + number_types.Int32Flags.bytewidth
+347
View File
@@ -0,0 +1,347 @@
Metadata-Version: 2.2
Name: h3
Version: 4.3.1
Summary: Uber's hierarchical hexagonal geospatial indexing system
Author-Email: Uber Technologies <ajfriend@gmail.com>
Maintainer-Email: AJ Friend <ajfriend@gmail.com>
License:
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: C
Classifier: Programming Language :: Cython
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: MacOS :: MacOS X
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: Microsoft :: Windows
Classifier: Topic :: Scientific/Engineering :: GIS
Project-URL: Homepage, https://github.com/uber/h3-py
Project-URL: Documentation, https://uber.github.io/h3-py/
Project-URL: Bug Tracker, https://github.com/uber/h3-py/issues
Project-URL: Discussions, https://github.com/uber/h3-py/discussions
Project-URL: Changelog, https://uber.github.io/h3-py/_changelog.html
Requires-Python: >=3.8
Provides-Extra: numpy
Requires-Dist: numpy; extra == "numpy"
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: ruff; extra == "test"
Requires-Dist: numpy; extra == "test"
Provides-Extra: all
Requires-Dist: h3[test]; extra == "all"
Requires-Dist: jupyter-book; extra == "all"
Requires-Dist: sphinx>=7.3.3; extra == "all"
Requires-Dist: jupyterlab; extra == "all"
Requires-Dist: jupyterlab-geojson; extra == "all"
Requires-Dist: geopandas; extra == "all"
Requires-Dist: geodatasets; extra == "all"
Requires-Dist: matplotlib; extra == "all"
Requires-Dist: contextily; extra == "all"
Requires-Dist: cartopy; extra == "all"
Requires-Dist: geoviews; extra == "all"
Description-Content-Type: text/markdown
<img align="right" src="https://uber.github.io/img/h3Logo-color.svg" alt="H3 Logo" width="130">
# **h3-py**: Uber's H3 Hexagonal Hierarchical Geospatial Indexing System in Python
[![PyPI version](https://badge.fury.io/py/h3.svg)](https://badge.fury.io/py/h3)
[![PyPI downloads](https://img.shields.io/pypi/dm/h3.svg)](https://pypistats.org/packages/h3)
[![conda](https://img.shields.io/conda/vn/conda-forge/h3-py.svg)](https://anaconda.org/conda-forge/h3-py)
[![version](https://img.shields.io/badge/h3-v4.3.0-blue.svg)](https://github.com/uber/h3/releases/tag/v4.3.0)
[![version](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/uber/h3-py/blob/master/LICENSE)
[![Tests](https://github.com/uber/h3-py/workflows/tests/badge.svg)](https://github.com/uber/h3-py/actions)
[![Coverage 100%](https://img.shields.io/badge/coverage-100%25-green.svg)](https://github.com/uber/h3-py/blob/master/.github/workflows/lint_and_coverage.yml#L31) <!-- 100% coverage is enforced in CI -->
Python bindings for the [H3 core library](https://h3geo.org/).
- Documentation: [uber.github.io/h3-py](https://uber.github.io/h3-py)
- GitHub repo: [github.com/uber/h3-py](https://github.com/uber/h3-py)
## Installation
From [PyPI](https://pypi.org/project/h3/):
```console
pip install h3
```
From [conda](https://github.com/conda-forge/h3-py-feedstock):
```console
conda config --add channels conda-forge
conda install h3-py
```
## Usage
```python
>>> import h3
>>> lat, lng = 37.769377, -122.388903
>>> resolution = 9
>>> h3.latlng_to_cell(lat, lng, resolution)
'89283082e73ffff'
```
## APIs
[api_comparison]: https://uber.github.io/h3-py/api_comparison
[api_quick]: https://uber.github.io/h3-py/api_quick
We provide [multiple APIs][api_comparison] in `h3-py`.
- All APIs have the same set of functions;
see the [API reference][api_quick].
- The APIs differ only in their input/output formats;
see the [API comparison page][api_comparison].
## Example gallery
Browse [a collection of example notebooks](https://github.com/uber/h3-py-notebooks),
and if you have examples or visualizations of your own, please feel free
to contribute!
[walkthrough]: https://nbviewer.jupyter.org/github/uber/h3-py-notebooks/blob/master/notebooks/usage.ipynb
We also have an introductory [walkthrough of the API][walkthrough].
## Versioning
<!-- todo: this should just be the h3.versions() docstring, yeah? -->
`h3-py` wraps the [H3 core library](https://github.com/uber/h3),
which is written in C.
The C and Python projects each employ
[semantic versioning](https://semver.org/),
where versions take the form `X.Y.Z`.
The `h3-py` version string is guaranteed to match the C library string
in both *major* and *minor* numbers (`X.Y`), but may differ on the
*patch* (`Z`) number.
This convention provides users with information on breaking changes and
feature additions, while providing downstream bindings (like this one!)
with the versioning freedom to fix bugs.
Use `h3.versions()` to see the version numbers for both
`h3-py` and the C library. For example,
```python
>>> import h3
>>> h3.versions()
{'c': '4.1.0', 'python': '4.1.1'}
```
+50
View File
@@ -0,0 +1,50 @@
h3/CMakeLists.txt,sha256=8zQ0011t8bmsJw_GiKOFbkTZnquBh6ESCMZyLrm9u_U,22
h3/__init__.py,sha256=-i_HfsVLg1wW2wX8p74WIxHXi7NPO1GSVtjILstnS8U,575
h3/_h3shape.py,sha256=hhsBJyuy5MqDhG_BixzbCTOfQgaO6Gf2olFEYd6iLKE,8559
h3/_version.py,sha256=Tjq_BBPmWroGgfnrf7u9TpAWss9iA5PnWSv8kkZkJY8,88
h3/_cy/CMakeLists.txt,sha256=-h6Dk_V8VYydmDht9zCOv7wbSOl_G4MtlajIrj2D8hE,1528
h3/_cy/__init__.py,sha256=-f0Zqm46bnFuV0-Vs2FJMhODzbL1Oow-zuRJQS5dBFs,2488
h3/_cy/cells.cpython-312-aarch64-linux-gnu.so,sha256=IT938GoA2i_KXkLbzfy84nZB85Jl9g4KSm7rdHWBHPY,469320
h3/_cy/cells.pxd,sha256=9GydN6Nc4vJFU0nVyCP8BvDA4P702OX2LDQdkAnHv9I,1326
h3/_cy/cells.pyx,sha256=TcEjufzELbfLGxQ10IA1aFX-nQt8sDx6JT_HhKQtsNc,9517
h3/_cy/edges.cpython-312-aarch64-linux-gnu.so,sha256=8nCk6r3A9PISVMLdzHTiatYt3dqNDeFkQ-sfemWmvYM,402824
h3/_cy/edges.pxd,sha256=_zUOkV8aeWhk_xjicSWBDHNOp3vMEeg8o2Da06iYn38,561
h3/_cy/edges.pyx,sha256=1ECoK-OP3_BplwLZqwqNwItMLNIja6kVMzMeo7maHz8,2487
h3/_cy/error_system.cpython-312-aarch64-linux-gnu.so,sha256=R4fc8to7fKrP7QBXX5KB7SXQzasH_vo81f7U6bGs1mk,202360
h3/_cy/error_system.pxd,sha256=Dd2LjHcmlkCcs5Tr_HSp7xcn8YsQq2Evk4HxtIZF9m4,109
h3/_cy/error_system.pyx,sha256=gyg7NPuY2nfsj2QnJC11OTZUCXLvNybpcgNC25Jor7E,6908
h3/_cy/h3api.h,sha256=lQHNByNGZG6AkVjpIB2OZEv7fnAbBfCGqe4oqx0Hgd0,26418
h3/_cy/h3lib.pxd,sha256=d37c0MiHuWQL28ogaxiLjKq1P4lh_gdIPRZrjizHi2g,6955
h3/_cy/latlng.cpython-312-aarch64-linux-gnu.so,sha256=Nr-18UTddm3XyqtmVqrxgbWPbihilri0Od-gE2FRr1Q,471768
h3/_cy/latlng.pxd,sha256=WjOjY4jH_2lK6hnaVXCusqLg2DvvZ4rvAJyXeCQd2uk,266
h3/_cy/latlng.pyx,sha256=FW8L4LEr6l7qhsRL28mFakVLHnfqSCKQDQ6Ued-nLks,8370
h3/_cy/memory.cpython-312-aarch64-linux-gnu.so,sha256=FXPAzIgzILQh4LxXlOchgkLY6_kpFWmzb3zsIFFL9lg,336208
h3/_cy/memory.pxd,sha256=jXGN68hdcPUyA_yFCesZxCksHwmHMO4Ah-I9ZwYBvXs,236
h3/_cy/memory.pyx,sha256=KZo65H3rXn290iH05ZNkyt78mKEGIaVjzmgYdOon_PU,7103
h3/_cy/to_multipoly.cpython-312-aarch64-linux-gnu.so,sha256=4r6p7uq0B_Ln85xK_P9HvC59LtTR-ZAXGYXMG8CUwBk,402440
h3/_cy/to_multipoly.pyx,sha256=bpaP3rGl5mtWTp1aH0ksL-gMi_tobSxjnZvxX6B2R4o,1369
h3/_cy/util.cpython-312-aarch64-linux-gnu.so,sha256=zIQQ7i19XEZiT4I6hMg3RdnXxb0ZDjRCU1ohQ9pwoxY,267856
h3/_cy/util.pxd,sha256=9JeCVVOOxfd3QoK4q_W-yIhmEASq_X2Y-A_Crn2bvZg,346
h3/_cy/util.pyx,sha256=9woUsIwPG18UmjDbw8QFNnIXT62HMOUKGUmGIKt_ONo,2348
h3/_cy/vertex.cpython-312-aarch64-linux-gnu.so,sha256=5-tDMKX5uWCv-2W3gVPhAwFbcB8f5q092KLuUa5oChA,337024
h3/_cy/vertex.pxd,sha256=lnRECjEFpohFr7iB6d2UrTN-s37UzXnSpaP_UV5866I,229
h3/_cy/vertex.pyx,sha256=_26ur2q3CZzb0BGQ85Lvbjq9dRWscvjAsKlgmCAqVHc,910
h3/api/__init__.py,sha256=X6P438-1N_2jWlFKNZ8q_jUop7ICRhwwa4I0RuxtQIQ,114
h3/api/basic_int/__init__.py,sha256=pg0QGCIGIyT0WTnD2vDqP-LyW0m5E1qd9F19l6wf3Rs,25924
h3/api/basic_int/_convert.py,sha256=GmVFFTT-mMHJ_Newx-6aF8TAtKBTrXglMx5RNV9w0Nk,187
h3/api/basic_str/__init__.py,sha256=pg0QGCIGIyT0WTnD2vDqP-LyW0m5E1qd9F19l6wf3Rs,25924
h3/api/basic_str/_convert.py,sha256=9B7uHdbUJhDb0GUEdSg-dUQpNCmvPviK6_DX99YS5UE,256
h3/api/memview_int/__init__.py,sha256=pg0QGCIGIyT0WTnD2vDqP-LyW0m5E1qd9F19l6wf3Rs,25924
h3/api/memview_int/_convert.py,sha256=ef5Omw0GJsUlR8r66O1p8f9IEEhCeTdDjlvN2A0urjA,105
h3/api/numpy_int/__init__.py,sha256=pg0QGCIGIyT0WTnD2vDqP-LyW0m5E1qd9F19l6wf3Rs,25924
h3/api/numpy_int/_convert.py,sha256=dhZLocPjucl6Uu872k1tAcuWXBRT29oUG8qFMoleulE,288
include/h3/h3api.h,sha256=lQHNByNGZG6AkVjpIB2OZEv7fnAbBfCGqe4oqx0Hgd0,26418
lib64/libh3.a,sha256=daDl9sRycc5tHGPbiHyd-IYfmyaXFQKnB-xES26wv4Q,170004
lib64/cmake/h3/h3Config.cmake,sha256=QwISc49jy-ZH9Ba1YCQnick54sapi_pZDEJjDJyMrb4,959
lib64/cmake/h3/h3ConfigVersion.cmake,sha256=Nf3JY8h9E9o1YHZ9TuUc_XN5CyS3yxa4pp5PTIEViKM,2762
lib64/cmake/h3/h3Targets-release.cmake,sha256=pnJffyu5LDg0GeSMTTwBoVLamlDKo8XrjrCEyN7aP0w,797
lib64/cmake/h3/h3Targets.cmake,sha256=K18pICoM546T1tLsCSvdLlnLf1-GyFYPqMq8G0mZobM,4217
h3-4.3.1.dist-info/METADATA,sha256=XJDmH460i2LSmjPAibQR_6XHyedrvDe_0tXZM3v-7n0,18459
h3-4.3.1.dist-info/WHEEL,sha256=uOikQdbS4EYP0OE7pa4p-weSIqjfixseckdKxHaHlvE,198
h3-4.3.1.dist-info/RECORD,,
h3-4.3.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
+7
View File
@@ -0,0 +1,7 @@
Wheel-Version: 1.0
Generator: scikit-build-core 0.11.5
Root-Is-Purelib: false
Tag: cp312-cp312-manylinux_2_17_aarch64
Tag: cp312-cp312-manylinux2014_aarch64
Tag: cp312-cp312-manylinux_2_28_aarch64
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -0,0 +1 @@
add_subdirectory(_cy)
+29
View File
@@ -0,0 +1,29 @@
# flake8: noqa
from .api.basic_str import *
from ._version import __version__
from ._cy import (
UnknownH3ErrorCode,
H3BaseException,
H3GridNavigationError,
H3MemoryError,
H3ValueError,
H3FailedError,
H3DomainError,
H3LatLngDomainError,
H3ResDomainError,
H3CellInvalidError,
H3DirEdgeInvalidError,
H3UndirEdgeInvalidError,
H3VertexInvalidError,
H3PentagonError,
H3DuplicateInputError,
H3NotNeighborsError,
H3ResMismatchError,
H3MemoryAllocError,
H3MemoryBoundsError,
H3OptionInvalidError,
)
+53
View File
@@ -0,0 +1,53 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
macro(add_cython_file filename)
add_custom_command(
OUTPUT "${filename}.c"
COMMENT
"Making ${CMAKE_CURRENT_BINARY_DIR}/${filename}.c from ${CMAKE_CURRENT_SOURCE_DIR}/${filename}.pyx"
COMMAND Python::Interpreter -m cython
"${CMAKE_CURRENT_SOURCE_DIR}/${filename}.pyx" --output-file "${filename}.c" -I ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS "${filename}.pyx"
VERBATIM)
python_add_library(${filename} MODULE "${filename}.c" WITH_SOABI)
set_property(TARGET ${filename} PROPERTY C_STANDARD 99)
target_link_libraries(${filename} PRIVATE h3)
install(TARGETS ${filename} LIBRARY DESTINATION ${SKBUILD_PROJECT_NAME}/_cy)
endmacro()
# GLOB pattern is recommended against
# https://cmake.org/cmake/help/v3.14/command/file.html?highlight=file#filesystem
add_cython_file(cells)
add_cython_file(edges)
add_cython_file(error_system)
add_cython_file(latlng)
add_cython_file(memory)
add_cython_file(vertex)
add_cython_file(to_multipoly)
add_cython_file(util)
# Include pyx and pxd files in distribution for use by Cython API
install(
FILES
cells.pxd
cells.pyx
edges.pxd
edges.pyx
error_system.pyx
h3lib.pxd
latlng.pxd
latlng.pyx
memory.pxd
memory.pyx
util.pxd
util.pyx
vertex.pxd
vertex.pyx
DESTINATION
${SKBUILD_PROJECT_NAME}/_cy
)
+112
View File
@@ -0,0 +1,112 @@
# flake8: noqa
"""
This module should serve as the interface between the C/Cython code and
the Python code. That is, it is an internal API.
This module should import all the Cython functions we
intend to expose to be used in pure Python code, and each of the H3-py
APIs should *only* reference functions and symbols listed here.
These functions should handle input validation, guard against the
possibility of segfaults, raise appropriate errors, and handle memory
management. The API wrapping code around this should focus on the cosmetic
function interface and input conversion (string to int, for instance).
"""
from .cells import (
is_valid_cell,
is_pentagon,
get_base_cell_number,
get_resolution,
cell_to_parent,
grid_distance,
grid_disk,
grid_ring,
cell_to_children_size,
cell_to_children,
cell_to_child_pos,
child_pos_to_cell,
compact_cells,
uncompact_cells,
get_num_cells,
average_hexagon_area,
cell_area,
grid_path_cells,
is_res_class_iii,
get_pentagons,
get_res0_cells,
cell_to_center_child,
get_icosahedron_faces,
cell_to_local_ij,
local_ij_to_cell,
)
from .edges import (
are_neighbor_cells,
cells_to_directed_edge,
is_valid_directed_edge,
get_directed_edge_origin,
get_directed_edge_destination,
directed_edge_to_cells,
origin_to_directed_edges,
average_hexagon_edge_length,
edge_length,
)
from .latlng import (
latlng_to_cell,
cell_to_latlng,
polygon_to_cells,
polygons_to_cells,
polygon_to_cells_experimental,
polygons_to_cells_experimental,
cell_to_boundary,
directed_edge_to_boundary,
great_circle_distance,
)
from .vertex import (
cell_to_vertex,
cell_to_vertexes,
vertex_to_latlng,
is_valid_vertex,
)
from .to_multipoly import (
cells_to_multi_polygon
)
from .util import (
c_version,
str_to_int,
int_to_str,
)
from .memory import (
iter_to_mv,
)
from .error_system import (
UnknownH3ErrorCode,
H3BaseException,
H3GridNavigationError,
H3MemoryError,
H3ValueError,
H3FailedError,
H3DomainError,
H3LatLngDomainError,
H3ResDomainError,
H3CellInvalidError,
H3DirEdgeInvalidError,
H3UndirEdgeInvalidError,
H3VertexInvalidError,
H3PentagonError,
H3DuplicateInputError,
H3NotNeighborsError,
H3ResMismatchError,
H3MemoryAllocError,
H3MemoryBoundsError,
H3OptionInvalidError,
)
+27
View File
@@ -0,0 +1,27 @@
from .h3lib cimport bool, int64_t, H3int
cpdef bool is_valid_cell(H3int h)
cpdef bool is_pentagon(H3int h)
cpdef int get_base_cell_number(H3int h) except -1
cpdef int get_resolution(H3int h) except -1
cpdef int grid_distance(H3int h1, H3int h2) except -1
cpdef H3int[:] grid_disk(H3int h, int k)
cpdef H3int[:] grid_ring(H3int h, int k)
cpdef H3int cell_to_parent(H3int h, res=*) except 0
cpdef int64_t cell_to_children_size(H3int h, res=*) except -1
cpdef H3int[:] cell_to_children(H3int h, res=*)
cpdef H3int cell_to_center_child(H3int h, res=*) except 0
cpdef int64_t cell_to_child_pos(H3int child, int parent_res) except -1
cpdef H3int child_pos_to_cell(H3int parent, int child_res, int64_t child_pos) except 0
cpdef H3int[:] compact_cells(const H3int[:] hu)
cpdef H3int[:] uncompact_cells(const H3int[:] hc, int res)
cpdef int64_t get_num_cells(int resolution) except -1
cpdef double average_hexagon_area(int resolution, unit=*) except -1
cpdef double cell_area(H3int h, unit=*) except -1
cpdef H3int[:] grid_path_cells(H3int start, H3int end)
cpdef bool is_res_class_iii(H3int h)
cpdef H3int[:] get_pentagons(int res)
cpdef H3int[:] get_res0_cells()
cpdef get_icosahedron_faces(H3int h)
cpdef (int, int) cell_to_local_ij(H3int origin, H3int h) except *
cpdef H3int local_ij_to_cell(H3int origin, int i, int j) except 0
+419
View File
@@ -0,0 +1,419 @@
cimport h3lib
from .h3lib cimport bool, int64_t, H3int, H3ErrorCodes
from .util cimport (
check_cell,
check_res, # we don't use?
check_distance,
)
from .error_system cimport (
check_for_error,
check_for_error_msg,
)
from .memory cimport (
H3MemoryManager,
int_mv,
)
# todo: add notes about Cython exception handling
# bool is a python type, so we don't need the except clause
cpdef bool is_valid_cell(H3int h):
"""Validates an H3 cell (hexagon or pentagon)
Returns
-------
boolean
"""
return h3lib.isValidCell(h) == 1
cpdef bool is_pentagon(H3int h):
return h3lib.isPentagon(h) == 1
cpdef int get_base_cell_number(H3int h) except -1:
check_cell(h)
return h3lib.getBaseCellNumber(h)
cpdef int get_resolution(H3int h) except -1:
"""Returns the resolution of an H3 Index
0--15
"""
check_cell(h)
return h3lib.getResolution(h)
cpdef int grid_distance(H3int h1, H3int h2) except -1:
""" Compute the grid distance between two cells
"""
cdef:
int64_t distance
check_cell(h1)
check_cell(h2)
check_for_error(
h3lib.gridDistance(h1, h2, &distance)
)
return distance
cpdef H3int[:] grid_disk(H3int h, int k):
""" Return cells at grid distance `<= k` from `h`.
"""
cdef:
int64_t n
check_cell(h)
check_distance(k)
check_for_error(
h3lib.maxGridDiskSize(k, &n)
)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.gridDisk(h, k, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef H3int[:] grid_ring(H3int h, int k):
""" Return cells at grid distance `== k` from `h`.
Collection is "hollow" for k >= 1.
"""
check_cell(h)
check_distance(k)
n = 6*k if k > 0 else 1
hmm = H3MemoryManager(n)
check_for_error(
h3lib.gridRing(h, k, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef H3int cell_to_parent(H3int h, res=None) except 0:
cdef:
H3int parent
check_cell(h)
if res is None:
res = get_resolution(h) - 1
err = h3lib.cellToParent(h, res, &parent)
if err:
msg = 'Invalid parent resolution {} for cell {}.'
msg = msg.format(res, hex(h))
check_for_error_msg(err, msg)
return parent
cpdef int64_t cell_to_children_size(H3int h, res=None) except -1:
cdef:
int64_t n
check_cell(h)
if res is None:
res = get_resolution(h) + 1
err = h3lib.cellToChildrenSize(h, res, &n)
if err:
msg = 'Invalid child resolution {} for cell {}.'
msg = msg.format(res, hex(h))
check_for_error_msg(err, msg)
return n
cpdef H3int[:] cell_to_children(H3int h, res=None):
check_cell(h)
if res is None:
res = get_resolution(h) + 1
n = cell_to_children_size(h, res)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.cellToChildren(h, res, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef H3int cell_to_center_child(H3int h, res=None) except 0:
cdef:
H3int child
check_cell(h)
if res is None:
res = get_resolution(h) + 1
err = h3lib.cellToCenterChild(h, res, &child)
if err:
msg = 'Invalid child resolution {} for cell {}.'
msg = msg.format(res, hex(h))
check_for_error_msg(err, msg)
return child
cpdef int64_t cell_to_child_pos(H3int child, int parent_res) except -1:
cdef:
int64_t child_pos
check_cell(child)
err = h3lib.cellToChildPos(child, parent_res, &child_pos)
if err:
msg = "Couldn't find child pos of cell {} at res {}."
msg = msg.format(hex(child), parent_res)
check_for_error_msg(err, msg)
return child_pos
cpdef H3int child_pos_to_cell(H3int parent, int child_res, int64_t child_pos) except 0:
cdef:
H3int child
check_cell(parent)
err = h3lib.childPosToCell(child_pos, parent, child_res, &child)
if err:
msg = "Couldn't find child with pos {} at res {} from parent {}."
msg = msg.format(child_pos, child_res, hex(parent))
check_for_error_msg(err, msg)
return child
cpdef H3int[:] compact_cells(const H3int[:] hu):
# todo: fix this with my own Cython object "wrapper" class?
# everything has a .ptr interface?
# todo: the Clib can handle 0-len arrays because it **avoids**
# dereferencing the pointer, but Cython's syntax of
# `&hu[0]` **requires** a dereference. For Cython, checking for array
# length of zero and returning early seems like the easiest solution.
# note: open to better ideas!
if len(hu) == 0:
return H3MemoryManager(0).to_mv()
for h in hu: ## todo: should we have an array version? would that be faster?
check_cell(h)
cdef size_t n = len(hu)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.compactCells(&hu[0], hmm.ptr, n)
)
mv = hmm.to_mv()
return mv
# todo: https://stackoverflow.com/questions/50684977/cython-exception-type-for-a-function-returning-a-typed-memoryview
# apparently, memoryviews are python objects, so we don't need to do the except clause
cpdef H3int[:] uncompact_cells(const H3int[:] hc, int res):
# todo: the Clib can handle 0-len arrays because it **avoids**
# dereferencing the pointer, but Cython's syntax of
# `&hc[0]` **requires** a dereference. For Cython, checking for array
# length of zero and returning early seems like the easiest solution.
# note: open to better ideas!
cdef:
int64_t n
if len(hc) == 0:
return H3MemoryManager(0).to_mv()
for h in hc:
check_cell(h)
check_for_error(
h3lib.uncompactCellsSize(&hc[0], len(hc), res, &n)
)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.uncompactCells(
&hc[0], # todo: symmetry here with the wrapper object might be nice. hc.ptr / hc.n
len(hc),
hmm.ptr,
hmm.n,
res
)
)
mv = hmm.to_mv()
return mv
cpdef int64_t get_num_cells(int resolution) except -1:
cdef:
int64_t num_cells
check_for_error(
h3lib.getNumCells(resolution, &num_cells)
)
return num_cells
cpdef double average_hexagon_area(int resolution, unit='km^2') except -1:
cdef:
double area
check_for_error(
h3lib.getHexagonAreaAvgKm2(resolution, &area)
)
# todo: multiple units
convert = {
'km^2': 1.0,
'm^2': 1000*1000.0
}
try:
area *= convert[unit]
except:
raise ValueError('Unknown unit: {}'.format(unit))
return area
cpdef double cell_area(H3int h, unit='km^2') except -1:
cdef:
double area
if unit == 'rads^2':
err = h3lib.cellAreaRads2(h, &area)
elif unit == 'km^2':
err = h3lib.cellAreaKm2(h, &area)
elif unit == 'm^2':
err = h3lib.cellAreaM2(h, &area)
else:
raise ValueError('Unknown unit: {}'.format(unit))
check_for_error(err)
return area
cdef _could_not_find_line(err, start, end):
msg = "Couldn't find line between cells {} and {}"
msg = msg.format(hex(start), hex(end))
check_for_error_msg(err, msg)
cpdef H3int[:] grid_path_cells(H3int start, H3int end):
cdef:
int64_t n
# todo: can we segfault here with invalid inputs?
# Can we trust the c library to validate the start/end cells?
# probably applies to all size/work pairs of functions...
err = h3lib.gridPathCellsSize(start, end, &n)
_could_not_find_line(err, start, end)
hmm = H3MemoryManager(n)
err = h3lib.gridPathCells(start, end, hmm.ptr)
_could_not_find_line(err, start, end)
# todo: probably here too?
mv = hmm.to_mv()
return mv
cpdef bool is_res_class_iii(H3int h):
return h3lib.isResClassIII(h) == 1
cpdef H3int[:] get_pentagons(int res):
n = h3lib.pentagonCount()
hmm = H3MemoryManager(n)
check_for_error(
h3lib.getPentagons(res, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef H3int[:] get_res0_cells():
n = h3lib.res0CellCount()
hmm = H3MemoryManager(n)
check_for_error(
h3lib.getRes0Cells(hmm.ptr)
)
mv = hmm.to_mv()
return mv
# oh, this is returning a set??
# todo: convert to int[:]?
cpdef get_icosahedron_faces(H3int h):
cdef:
int n
int[:] faces ## todo: weird, this needs to be specified to avoid errors. cython bug?
check_for_error(
h3lib.maxFaceCount(h, &n)
)
faces = int_mv(n)
check_for_error(
h3lib.getIcosahedronFaces(h, &faces[0])
)
# todo: wait? do faces start from 0 or 1?
# we could do this check/processing in the int_mv object
out = [f for f in faces if f >= 0]
return out
cpdef (int, int) cell_to_local_ij(H3int origin, H3int h) except *:
cdef:
h3lib.CoordIJ c
err = h3lib.cellToLocalIj(origin, h, 0, &c)
if err:
msg = "Couldn't find local (i,j) between cells {} and {}."
msg = msg.format(hex(origin), hex(h))
check_for_error_msg(err, msg)
return c.i, c.j
cpdef H3int local_ij_to_cell(H3int origin, int i, int j) except 0:
cdef:
h3lib.CoordIJ c
H3int out
c.i, c.j = i, j
err = h3lib.localIjToCell(origin, &c, 0, &out)
if err:
msg = "Couldn't find cell at local ({},{}) from cell {}."
msg = msg.format(i, j, hex(origin))
check_for_error_msg(err, msg)
return out
+11
View File
@@ -0,0 +1,11 @@
from .h3lib cimport bool, H3int
cpdef bool are_neighbor_cells(H3int h1, H3int h2)
cpdef H3int cells_to_directed_edge(H3int origin, H3int destination) except *
cpdef bool is_valid_directed_edge(H3int e)
cpdef H3int get_directed_edge_origin(H3int e) except 1
cpdef H3int get_directed_edge_destination(H3int e) except 1
cpdef (H3int, H3int) directed_edge_to_cells(H3int e) except *
cpdef H3int[:] origin_to_directed_edges(H3int origin)
cpdef double average_hexagon_edge_length(int resolution, unit=*) except -1
cpdef double edge_length(H3int e, unit=*) except -1
+114
View File
@@ -0,0 +1,114 @@
cimport h3lib
from .h3lib cimport bool, H3int
from .error_system cimport check_for_error
from .memory cimport H3MemoryManager
# todo: make bint
cpdef bool are_neighbor_cells(H3int h1, H3int h2):
cdef:
int out
err = h3lib.areNeighborCells(h1, h2, &out)
# note: we are intentionally not raising an error here, and just
# returning false.
# todo: is this choice consistent across the Python and C libs?
if err:
return False
return out == 1
cpdef H3int cells_to_directed_edge(H3int origin, H3int destination) except *:
cdef:
int neighbor_out
H3int out
check_for_error(
h3lib.cellsToDirectedEdge(origin, destination, &out)
)
return out
cpdef bool is_valid_directed_edge(H3int e):
return h3lib.isValidDirectedEdge(e) == 1
cpdef H3int get_directed_edge_origin(H3int e) except 1:
cdef:
H3int out
check_for_error(
h3lib.getDirectedEdgeOrigin(e, &out)
)
return out
cpdef H3int get_directed_edge_destination(H3int e) except 1:
cdef:
H3int out
check_for_error(
h3lib.getDirectedEdgeDestination(e, &out)
)
return out
cpdef (H3int, H3int) directed_edge_to_cells(H3int e) except *:
# todo: use directed_edge_to_cells in h3lib
return get_directed_edge_origin(e), get_directed_edge_destination(e)
cpdef H3int[:] origin_to_directed_edges(H3int origin):
""" Returns the 6 (or 5 for pentagons) directed edges
for the given origin cell
"""
hmm = H3MemoryManager(6)
check_for_error(
h3lib.originToDirectedEdges(origin, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef double average_hexagon_edge_length(int resolution, unit='km') except -1:
cdef:
double length
check_for_error(
h3lib.getHexagonEdgeLengthAvgKm(resolution, &length)
)
# todo: multiple units
convert = {
'km': 1.0,
'm': 1000.0
}
try:
length *= convert[unit]
except:
raise ValueError('Unknown unit: {}'.format(unit))
return length
cpdef double edge_length(H3int e, unit='km') except -1:
cdef:
double length
if unit == 'rads':
err = h3lib.edgeLengthRads(e, &length)
elif unit == 'km':
err = h3lib.edgeLengthKm(e, &length)
elif unit == 'm':
err = h3lib.edgeLengthM(e, &length)
else:
raise ValueError('Unknown unit: {}'.format(unit))
check_for_error(err)
return length
+3
View File
@@ -0,0 +1,3 @@
from .h3lib cimport H3Error
cdef check_for_error(H3Error err)
cdef check_for_error_msg(H3Error err, str msg)
+231
View File
@@ -0,0 +1,231 @@
"""
Exceptions from the h3-py library have three possible sources:
- the Python code
- the Cython code
- the underlying H3 C library code
The Python and Cython `h3-py` code will only raise standard Python
built-in exceptions; **no custom** exception classes will be used.
Conversely, many functions in the H3 C library return a `uint32_t`
error code (aliased as type `H3Error`).
When these errors happen (and `h3-py` can't recover from them internally),
they are passed up to the Python/Cython code, where their
`uint32_t` error values are converted to **custom** Python exception types.
These custom exception classes all inherit from `H3BaseException`.
There is a 1-1 correspondence between the concrete subclasses of
`H3BaseException` and the H3 C library `H3ErrorCodes` values.
The correspondence is intentional, so that the user can refer to the
H3 C library documentation on these errors.
The (`uint32_t` <-> Exception) correspondence should be clear from
the names of each error/exception, but the explicit mapping is given by
a dictionary in the code below.
Note that some "abstract" subclasses of `H3BaseException` are also included to
group the exceptions by type. (We say "abstract" because Python has no easy
way to make true abstract exception classes.)
These "abstract" exceptions will never be raised directly by `h3-py`, but they
allow the user to catch general groups of errors.
Note that `h3-py` will only ever directly raise
the "concrete" exception classes.
Summarizing, all exceptions originating from the C library inherit from
`H3BaseException`, which has both "abstract" and "concrete" subclasses.
**Abstract classes**:
- H3BaseException
- H3ValueError
- H3MemoryError
- H3GridNavigationError
**Concrete classes**:
- H3FailedError
- H3DomainError
- H3LatLngDomainError
- H3ResDomainError
- H3CellInvalidError
- H3DirEdgeInvalidError
- H3UndirEdgeInvalidError
- H3VertexInvalidError
- H3PentagonError
- H3DuplicateInputError
- H3NotNeighborsError
- H3ResMismatchError
- H3MemoryAllocError
- H3MemoryBoundsError
- H3OptionInvalidError
# TODO: add tests verifying that concrete exception classes have the right error codes associated with them
"""
from contextlib import contextmanager
from .h3lib cimport (
H3Error,
# H3ErrorCodes enum values
E_SUCCESS,
E_FAILED,
E_DOMAIN,
E_LATLNG_DOMAIN,
E_RES_DOMAIN,
E_CELL_INVALID,
E_DIR_EDGE_INVALID,
E_UNDIR_EDGE_INVALID,
E_VERTEX_INVALID,
E_PENTAGON,
E_DUPLICATE_INPUT,
E_NOT_NEIGHBORS,
E_RES_MISMATCH,
E_MEMORY_ALLOC,
E_MEMORY_BOUNDS,
E_OPTION_INVALID,
)
@contextmanager
def _the_error(obj):
"""
Syntactic maple syrup for grouping exception definitions.
The associated `with` statement ends up as a not-half-bad
approximation to a valid sentence fragment.
This provides sort of a "pretend scope", in that it allows for
block indentation which helps to visually indicate the "scope"
of the `... as e` statement. Just note that Python doesn't treat the
`with` block as a "true" separate scope.
Note that this doesn't actually do anything context-manager-y, outside
of the variable assignment and block indentation.
"""
yield obj
#
# Base exception for C library error codes
#
class H3BaseException(Exception):
""" Base H3 exception class.
Concrete subclasses of this class correspond to specific
error codes from the C library.
Base/abstract subclasses will have `h3_error_code = None`, while
concrete subclasses will have `h3_error_code` equal to their associated
C library error code.
"""
h3_error_code = None
#
# A few "abstract" exceptions; organizational.
#
with _the_error(H3BaseException) as e:
class H3ValueError(e, ValueError): ...
class H3MemoryError(e, MemoryError): ...
class H3GridNavigationError(e, RuntimeError): ...
#
# Concrete exceptions
#
class UnknownH3ErrorCode(H3BaseException):
"""
Indicates that the h3-py Python bindings have received an
unrecognized error code from the C library.
This should never happen. Please report if you get this error.
Note that this exception is *outside* of the
H3BaseException class hierarchy.
"""
pass
with _the_error(H3BaseException) as e:
class H3FailedError(e): ...
with _the_error(H3GridNavigationError) as e:
class H3PentagonError(e): ...
with _the_error(H3MemoryError) as e:
class H3MemoryAllocError(e): ...
class H3MemoryBoundsError(e): ...
with _the_error(H3ValueError) as e:
class H3DomainError(e): ...
class H3LatLngDomainError(e): ...
class H3ResDomainError(e): ...
class H3CellInvalidError(e): ...
class H3DirEdgeInvalidError(e): ...
class H3UndirEdgeInvalidError(e): ...
class H3VertexInvalidError(e): ...
class H3DuplicateInputError(e): ...
class H3NotNeighborsError(e): ...
class H3ResMismatchError(e): ...
class H3OptionInvalidError(e): ...
"""
This defines a mapping between uint32_t error codes and concrete Python
exception classes.
Note that we intentionally omit E_SUCCESS, as it isn't an actual error.
"""
error_mapping = {
E_FAILED: H3FailedError,
E_DOMAIN: H3DomainError,
E_LATLNG_DOMAIN: H3LatLngDomainError,
E_RES_DOMAIN: H3ResDomainError,
E_CELL_INVALID: H3CellInvalidError,
E_DIR_EDGE_INVALID: H3DirEdgeInvalidError,
E_UNDIR_EDGE_INVALID: H3UndirEdgeInvalidError,
E_VERTEX_INVALID: H3VertexInvalidError,
E_PENTAGON: H3PentagonError,
E_DUPLICATE_INPUT: H3DuplicateInputError,
E_NOT_NEIGHBORS: H3NotNeighborsError,
E_RES_MISMATCH: H3ResMismatchError,
E_MEMORY_ALLOC: H3MemoryAllocError,
E_MEMORY_BOUNDS: H3MemoryBoundsError,
E_OPTION_INVALID: H3OptionInvalidError,
}
# Go back and modify the class definitions so that each concrete exception
# stores its associated error code.
for code, ex in error_mapping.items():
ex.h3_error_code = code
#
# Helper functions
#
# TODO: Move the helpers to util?
# TODO: Unclear how/where to expose these functions. cdef/cpdef?
cdef code_to_exception(H3Error err):
if err == E_SUCCESS:
return None
elif err in error_mapping:
return error_mapping[err]
else:
raise UnknownH3ErrorCode(err)
cdef check_for_error(H3Error err):
ex = code_to_exception(err)
if ex:
raise ex
# todo: There's no easy way to do `*args` in `cdef` functions, but I'm also
# not sure this even needs to be a Cython `cdef` function at all, or that
# any of the other helper functions need to be in Cython.
# todo: Revisit after we've played with this a bit.
# todo: also: maybe the extra messages aren't that much more helpful...
cdef check_for_error_msg(H3Error err, str msg):
ex = code_to_exception(err)
if ex:
raise ex(msg)
+809
View File
@@ -0,0 +1,809 @@
/*
* Copyright 2016-2021 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file h3api.h
* @brief Primary H3 core library entry points.
*
* This file defines the public API of the H3 library. Incompatible changes to
* these functions require the library's major version be increased.
*/
#ifndef H3API_H
#define H3API_H
/*
* Preprocessor code to support renaming (prefixing) the public API.
* All public functions should be wrapped in H3_EXPORT so they can be
* renamed.
*/
#ifdef H3_PREFIX
#define XTJOIN(a, b) a##b
#define TJOIN(a, b) XTJOIN(a, b)
/* export joins the user provided prefix with our exported function name */
#define H3_EXPORT(name) TJOIN(H3_PREFIX, name)
#else
#define H3_EXPORT(name) name
#endif
/* Windows DLL requires attributes indicating what to export */
#if _WIN32 && BUILD_SHARED_LIBS
#if BUILDING_H3
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif
#else
#define DECLSPEC
#endif
/* For uint64_t */
#include <stdint.h>
/* For size_t */
#include <stdlib.h>
/*
* H3 is compiled as C, not C++ code. `extern "C"` is needed for C++ code
* to be able to use the library.
*/
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Identifier for an object (cell, edge, etc) in the H3 system.
*
* The H3Index fits within a 64-bit unsigned integer.
*/
typedef uint64_t H3Index;
/**
* Invalid index used to indicate an error from latLngToCell and related
* functions or missing data in arrays of H3 indices. Analogous to NaN in
* floating point.
*/
#define H3_NULL 0
/** @brief Result code (success or specific error) from an H3 operation */
typedef uint32_t H3Error;
typedef enum {
E_SUCCESS = 0, // Success (no error)
E_FAILED =
1, // The operation failed but a more specific error is not available
E_DOMAIN = 2, // Argument was outside of acceptable range (when a more
// specific error code is not available)
E_LATLNG_DOMAIN =
3, // Latitude or longitude arguments were outside of acceptable range
E_RES_DOMAIN = 4, // Resolution argument was outside of acceptable range
E_CELL_INVALID = 5, // `H3Index` cell argument was not valid
E_DIR_EDGE_INVALID = 6, // `H3Index` directed edge argument was not valid
E_UNDIR_EDGE_INVALID =
7, // `H3Index` undirected edge argument was not valid
E_VERTEX_INVALID = 8, // `H3Index` vertex argument was not valid
E_PENTAGON = 9, // Pentagon distortion was encountered which the algorithm
// could not handle it
E_DUPLICATE_INPUT = 10, // Duplicate input was encountered in the arguments
// and the algorithm could not handle it
E_NOT_NEIGHBORS = 11, // `H3Index` cell arguments were not neighbors
E_RES_MISMATCH =
12, // `H3Index` cell arguments had incompatible resolutions
E_MEMORY_ALLOC = 13, // Necessary memory allocation failed
E_MEMORY_BOUNDS = 14, // Bounds of provided memory were not large enough
E_OPTION_INVALID = 15 // Mode or flags argument was not valid.
} H3ErrorCodes;
/** @defgroup describeH3Error describeH3Error
* Functions for describeH3Error
* @{
*/
/** @brief converts the provided H3Error value into a description string */
DECLSPEC const char *H3_EXPORT(describeH3Error)(H3Error err);
/** @} */
/* library version numbers generated from VERSION file */
// clang-format off
#define H3_VERSION_MAJOR 4
#define H3_VERSION_MINOR 3
#define H3_VERSION_PATCH 0
// clang-format on
/** Maximum number of cell boundary vertices; worst case is pentagon:
* 5 original verts + 5 edge crossings
*/
#define MAX_CELL_BNDRY_VERTS 10
/** @struct LatLng
@brief latitude/longitude in radians
*/
typedef struct {
double lat; ///< latitude in radians
double lng; ///< longitude in radians
} LatLng;
/** @struct CellBoundary
@brief cell boundary in latitude/longitude
*/
typedef struct {
int numVerts; ///< number of vertices
LatLng verts[MAX_CELL_BNDRY_VERTS]; ///< vertices in ccw order
} CellBoundary;
/** @struct GeoLoop
* @brief similar to CellBoundary, but requires more alloc work
*/
typedef struct {
int numVerts;
LatLng *verts;
} GeoLoop;
/** @struct GeoPolygon
* @brief Simplified core of GeoJSON Polygon coordinates definition
*/
typedef struct {
GeoLoop geoloop; ///< exterior boundary of the polygon
int numHoles; ///< number of elements in the array pointed to by holes
GeoLoop *holes; ///< interior boundaries (holes) in the polygon
} GeoPolygon;
/** @struct GeoMultiPolygon
* @brief Simplified core of GeoJSON MultiPolygon coordinates definition
*/
typedef struct {
int numPolygons;
GeoPolygon *polygons;
} GeoMultiPolygon;
/**
* Values representing polyfill containment modes, to be used in
* the `flags` bit field for `polygonToCellsExperimental`.
*/
typedef enum {
CONTAINMENT_CENTER = 0, ///< Cell center is contained in the shape
CONTAINMENT_FULL = 1, ///< Cell is fully contained in the shape
CONTAINMENT_OVERLAPPING = 2, ///< Cell overlaps the shape at any point
CONTAINMENT_OVERLAPPING_BBOX = 3, ///< Cell bounding box overlaps shape
CONTAINMENT_INVALID = 4 ///< This mode is invalid and should not be used
} ContainmentMode;
/** @struct LinkedLatLng
* @brief A coordinate node in a linked geo structure, part of a linked list
*/
typedef struct LinkedLatLng LinkedLatLng;
struct LinkedLatLng {
LatLng vertex;
LinkedLatLng *next;
};
/** @struct LinkedGeoLoop
* @brief A loop node in a linked geo structure, part of a linked list
*/
typedef struct LinkedGeoLoop LinkedGeoLoop;
struct LinkedGeoLoop {
LinkedLatLng *first;
LinkedLatLng *last;
LinkedGeoLoop *next;
};
/** @struct LinkedGeoPolygon
* @brief A polygon node in a linked geo structure, part of a linked list.
*/
typedef struct LinkedGeoPolygon LinkedGeoPolygon;
struct LinkedGeoPolygon {
LinkedGeoLoop *first;
LinkedGeoLoop *last;
LinkedGeoPolygon *next;
};
/** @struct CoordIJ
* @brief IJ hexagon coordinates
*
* Each axis is spaced 120 degrees apart.
*/
typedef struct {
int i; ///< i component
int j; ///< j component
} CoordIJ;
/** @defgroup latLngToCell latLngToCell
* Functions for latLngToCell
* @{
*/
/** @brief find the H3 index of the resolution res cell containing the lat/lng
*/
DECLSPEC H3Error H3_EXPORT(latLngToCell)(const LatLng *g, int res,
H3Index *out);
/** @} */
/** @defgroup cellToLatLng cellToLatLng
* Functions for cellToLatLng
* @{
*/
/** @brief find the lat/lng center point g of the cell h3 */
DECLSPEC H3Error H3_EXPORT(cellToLatLng)(H3Index h3, LatLng *g);
/** @} */
/** @defgroup cellToBoundary cellToBoundary
* Functions for cellToBoundary
* @{
*/
/** @brief give the cell boundary in lat/lng coordinates for the cell h3 */
DECLSPEC H3Error H3_EXPORT(cellToBoundary)(H3Index h3, CellBoundary *gp);
/** @} */
/** @defgroup gridDisk gridDisk
* Functions for gridDisk
* @{
*/
/** @brief maximum number of hexagons in k-ring */
DECLSPEC H3Error H3_EXPORT(maxGridDiskSize)(int k, int64_t *out);
/** @brief hexagons neighbors in all directions, assuming no pentagons */
DECLSPEC H3Error H3_EXPORT(gridDiskUnsafe)(H3Index origin, int k, H3Index *out);
/** @} */
/** @brief hexagons neighbors in all directions, assuming no pentagons,
* reporting distance from origin */
DECLSPEC H3Error H3_EXPORT(gridDiskDistancesUnsafe)(H3Index origin, int k,
H3Index *out,
int *distances);
/** @brief hexagons neighbors in all directions reporting distance from origin
*/
DECLSPEC H3Error H3_EXPORT(gridDiskDistancesSafe)(H3Index origin, int k,
H3Index *out, int *distances);
/** @brief collection of hex rings sorted by ring for all given hexagons */
DECLSPEC H3Error H3_EXPORT(gridDisksUnsafe)(H3Index *h3Set, int length, int k,
H3Index *out);
/** @brief hexagon neighbors in all directions */
DECLSPEC H3Error H3_EXPORT(gridDisk)(H3Index origin, int k, H3Index *out);
/** @} */
/** @defgroup gridDiskDistances gridDiskDistances
* Functions for gridDiskDistances
* @{
*/
/** @brief hexagon neighbors in all directions, reporting distance from origin
*/
DECLSPEC H3Error H3_EXPORT(gridDiskDistances)(H3Index origin, int k,
H3Index *out, int *distances);
/** @} */
/** @defgroup gridRing gridRing
* Functions for gridRing
* @{
*/
/** @brief maximum number of hexagons in hollow k-ring */
DECLSPEC H3Error H3_EXPORT(maxGridRingSize)(int k, int64_t *out);
/** @brief hollow hexagon ring k distance from origin */
DECLSPEC H3Error H3_EXPORT(gridRingUnsafe)(H3Index origin, int k, H3Index *out);
/** @brief hollow hexagon ring k distance from origin */
DECLSPEC H3Error H3_EXPORT(gridRing)(H3Index origin, int k, H3Index *out);
/** @} */
/** @defgroup polygonToCells polygonToCells
* Functions for polygonToCells
* @{
*/
/** @brief maximum number of cells that could be in the polygon */
DECLSPEC H3Error H3_EXPORT(maxPolygonToCellsSize)(const GeoPolygon *geoPolygon,
int res, uint32_t flags,
int64_t *out);
/** @brief cells within the given polygon */
DECLSPEC H3Error H3_EXPORT(polygonToCells)(const GeoPolygon *geoPolygon,
int res, uint32_t flags,
H3Index *out);
/** @} */
/** @defgroup polygonToCellsExperimental polygonToCellsExperimental
* Functions for polygonToCellsExperimental.
* This is an experimental-only API and is subject to change in minor versions.
* @{
*/
/** @brief maximum number of cells that could be in the polygon */
DECLSPEC H3Error H3_EXPORT(maxPolygonToCellsSizeExperimental)(
const GeoPolygon *polygon, int res, uint32_t flags, int64_t *out);
/** @brief cells within the given polygon */
DECLSPEC H3Error H3_EXPORT(polygonToCellsExperimental)(
const GeoPolygon *polygon, int res, uint32_t flags, int64_t size,
H3Index *out);
/** @} */
/** @defgroup cellsToMultiPolygon cellsToMultiPolygon
* Functions for cellsToMultiPolygon (currently a binding-only concept)
* @{
*/
/** @brief Create a LinkedGeoPolygon from a set of contiguous hexagons */
DECLSPEC H3Error H3_EXPORT(cellsToLinkedMultiPolygon)(const H3Index *h3Set,
const int numHexes,
LinkedGeoPolygon *out);
/** @brief Free all memory created for a LinkedGeoPolygon */
DECLSPEC void H3_EXPORT(destroyLinkedMultiPolygon)(LinkedGeoPolygon *polygon);
/** @} */
/** @defgroup degsToRads degsToRads
* Functions for degsToRads
* @{
*/
/** @brief converts degrees to radians */
DECLSPEC double H3_EXPORT(degsToRads)(double degrees);
/** @} */
/** @defgroup radsToDegs radsToDegs
* Functions for radsToDegs
* @{
*/
/** @brief converts radians to degrees */
DECLSPEC double H3_EXPORT(radsToDegs)(double radians);
/** @} */
/** @defgroup greatCircleDistance greatCircleDistance
* Functions for distance
* @{
*/
/** @brief "great circle distance" between pairs of LatLng points in radians*/
DECLSPEC double H3_EXPORT(greatCircleDistanceRads)(const LatLng *a,
const LatLng *b);
/** @brief "great circle distance" between pairs of LatLng points in
* kilometers*/
DECLSPEC double H3_EXPORT(greatCircleDistanceKm)(const LatLng *a,
const LatLng *b);
/** @brief "great circle distance" between pairs of LatLng points in meters*/
DECLSPEC double H3_EXPORT(greatCircleDistanceM)(const LatLng *a,
const LatLng *b);
/** @} */
/** @defgroup getHexagonAreaAvg getHexagonAreaAvg
* Functions for getHexagonAreaAvg
* @{
*/
/** @brief average hexagon area in square kilometers (excludes pentagons) */
DECLSPEC H3Error H3_EXPORT(getHexagonAreaAvgKm2)(int res, double *out);
/** @brief average hexagon area in square meters (excludes pentagons) */
DECLSPEC H3Error H3_EXPORT(getHexagonAreaAvgM2)(int res, double *out);
/** @} */
/** @defgroup cellArea cellArea
* Functions for cellArea
* @{
*/
/** @brief exact area for a specific cell (hexagon or pentagon) in radians^2 */
DECLSPEC H3Error H3_EXPORT(cellAreaRads2)(H3Index h, double *out);
/** @brief exact area for a specific cell (hexagon or pentagon) in kilometers^2
*/
DECLSPEC H3Error H3_EXPORT(cellAreaKm2)(H3Index h, double *out);
/** @brief exact area for a specific cell (hexagon or pentagon) in meters^2 */
DECLSPEC H3Error H3_EXPORT(cellAreaM2)(H3Index h, double *out);
/** @} */
/** @defgroup getHexagonEdgeLengthAvg getHexagonEdgeLengthAvg
* Functions for getHexagonEdgeLengthAvg
* @{
*/
/** @brief average hexagon edge length in kilometers (excludes pentagons) */
DECLSPEC H3Error H3_EXPORT(getHexagonEdgeLengthAvgKm)(int res, double *out);
/** @brief average hexagon edge length in meters (excludes pentagons) */
DECLSPEC H3Error H3_EXPORT(getHexagonEdgeLengthAvgM)(int res, double *out);
/** @} */
/** @defgroup edgeLength edgeLength
* Functions for edgeLength
* @{
*/
/** @brief exact length for a specific directed edge in radians*/
DECLSPEC H3Error H3_EXPORT(edgeLengthRads)(H3Index edge, double *length);
/** @brief exact length for a specific directed edge in kilometers*/
DECLSPEC H3Error H3_EXPORT(edgeLengthKm)(H3Index edge, double *length);
/** @brief exact length for a specific directed edge in meters*/
DECLSPEC H3Error H3_EXPORT(edgeLengthM)(H3Index edge, double *length);
/** @} */
/** @defgroup getNumCells getNumCells
* Functions for getNumCells
* @{
*/
/** @brief number of cells (hexagons and pentagons) for a given resolution
*
* It works out to be `2 + 120*7^r` for resolution `r`.
*
* # Mathematical notes
*
* Let h(n) be the number of children n levels below
* a single *hexagon*.
*
* Then h(n) = 7^n.
*
* Let p(n) be the number of children n levels below
* a single *pentagon*.
*
* Then p(0) = 1, and p(1) = 6, since each pentagon
* has 5 hexagonal immediate children and 1 pentagonal
* immediate child.
*
* In general, we have the recurrence relation
*
* p(n) = 5*h(n-1) + p(n-1)
* = 5*7^(n-1) + p(n-1).
*
* Working through the recurrence, we get that
*
* p(n) = 1 + 5*\sum_{k=1}^n 7^{k-1}
* = 1 + 5*(7^n - 1)/6,
*
* using the closed form for a geometric series.
*
* Using the closed forms for h(n) and p(n), we can
* get a closed form for the total number of cells
* at resolution r:
*
* c(r) = 12*p(r) + 110*h(r)
* = 2 + 120*7^r.
*
*
* @param res H3 cell resolution
*
* @return number of cells at resolution `res`
*/
DECLSPEC H3Error H3_EXPORT(getNumCells)(int res, int64_t *out);
/** @} */
/** @defgroup getRes0Cells getRes0Cells
* Functions for getRes0Cells
* @{
*/
/** @brief returns the number of resolution 0 cells (hexagons and pentagons) */
DECLSPEC int H3_EXPORT(res0CellCount)(void);
/** @brief provides all base cells in H3Index format*/
DECLSPEC H3Error H3_EXPORT(getRes0Cells)(H3Index *out);
/** @} */
/** @defgroup getPentagons getPentagons
* Functions for getPentagons
* @{
*/
/** @brief returns the number of pentagons per resolution */
DECLSPEC int H3_EXPORT(pentagonCount)(void);
/** @brief generates all pentagons at the specified resolution */
DECLSPEC H3Error H3_EXPORT(getPentagons)(int res, H3Index *out);
/** @} */
/** @defgroup getResolution getResolution
* Functions for getResolution
* @{
*/
/** @brief returns the resolution of the provided H3 index
* Works on both cells and directed edges. */
DECLSPEC int H3_EXPORT(getResolution)(H3Index h);
/** @} */
/** @defgroup getBaseCellNumber getBaseCellNumber
* Functions for getBaseCellNumber
* @{
*/
/** @brief returns the base cell "number" (0 to 121) of the provided H3 cell
*
* Note: Technically works on H3 edges, but will return base cell of the
* origin cell. */
DECLSPEC int H3_EXPORT(getBaseCellNumber)(H3Index h);
/** @} */
/** @defgroup stringToH3 stringToH3
* Functions for stringToH3
* @{
*/
/** @brief converts the canonical string format to H3Index format */
DECLSPEC H3Error H3_EXPORT(stringToH3)(const char *str, H3Index *out);
/** @} */
/** @defgroup h3ToString h3ToString
* Functions for h3ToString
* @{
*/
/** @brief converts an H3Index to a canonical string */
DECLSPEC H3Error H3_EXPORT(h3ToString)(H3Index h, char *str, size_t sz);
/** @} */
/** @defgroup isValidCell isValidCell
* Functions for isValidCell
* @{
*/
/** @brief confirms if an H3Index is a valid cell (hexagon or pentagon)
* In particular, returns 0 (False) for H3 directed edges or invalid data
*/
DECLSPEC int H3_EXPORT(isValidCell)(H3Index h);
/** @} */
/** @defgroup cellToParent cellToParent
* Functions for cellToParent
* @{
*/
/** @brief returns the parent (or grandparent, etc) cell of the given cell
*/
DECLSPEC H3Error H3_EXPORT(cellToParent)(H3Index h, int parentRes,
H3Index *parent);
/** @} */
/** @defgroup cellToChildren cellToChildren
* Functions for cellToChildren
* @{
*/
/** @brief determines the exact number of children (or grandchildren, etc)
* that would be returned for the given cell */
DECLSPEC H3Error H3_EXPORT(cellToChildrenSize)(H3Index h, int childRes,
int64_t *out);
/** @brief provides the children (or grandchildren, etc) of the given cell */
DECLSPEC H3Error H3_EXPORT(cellToChildren)(H3Index h, int childRes,
H3Index *children);
/** @} */
/** @defgroup cellToCenterChild cellToCenterChild
* Functions for cellToCenterChild
* @{
*/
/** @brief returns the center child of the given cell at the specified
* resolution */
DECLSPEC H3Error H3_EXPORT(cellToCenterChild)(H3Index h, int childRes,
H3Index *child);
/** @} */
/** @defgroup cellToChildPos cellToChildPos
* Functions for cellToChildPos
* @{
*/
/** @brief Returns the position of the cell within an ordered list of all
* children of the cell's parent at the specified resolution */
DECLSPEC H3Error H3_EXPORT(cellToChildPos)(H3Index child, int parentRes,
int64_t *out);
/** @} */
/** @defgroup childPosToCell childPosToCell
* Functions for childPosToCell
* @{
*/
/** @brief Returns the child cell at a given position within an ordered list of
* all children at the specified resolution */
DECLSPEC H3Error H3_EXPORT(childPosToCell)(int64_t childPos, H3Index parent,
int childRes, H3Index *child);
/** @} */
/** @defgroup compactCells compactCells
* Functions for compactCells
* @{
*/
/** @brief compacts the given set of hexagons as best as possible */
DECLSPEC H3Error H3_EXPORT(compactCells)(const H3Index *h3Set,
H3Index *compactedSet,
const int64_t numHexes);
/** @} */
/** @defgroup uncompactCells uncompactCells
* Functions for uncompactCells
* @{
*/
/** @brief determines the exact number of hexagons that will be uncompacted
* from the compacted set */
DECLSPEC H3Error H3_EXPORT(uncompactCellsSize)(const H3Index *compactedSet,
const int64_t numCompacted,
const int res, int64_t *out);
/** @brief uncompacts the compacted hexagon set */
DECLSPEC H3Error H3_EXPORT(uncompactCells)(const H3Index *compactedSet,
const int64_t numCompacted,
H3Index *outSet,
const int64_t numOut, const int res);
/** @} */
/** @defgroup isResClassIII isResClassIII
* Functions for isResClassIII
* @{
*/
/** @brief determines if a hexagon is Class III (or Class II) */
DECLSPEC int H3_EXPORT(isResClassIII)(H3Index h);
/** @} */
/** @defgroup isPentagon isPentagon
* Functions for isPentagon
* @{
*/
/** @brief determines if an H3 cell is a pentagon */
DECLSPEC int H3_EXPORT(isPentagon)(H3Index h);
/** @} */
/** @defgroup getIcosahedronFaces getIcosahedronFaces
* Functions for getIcosahedronFaces
* @{
*/
/** @brief Max number of icosahedron faces intersected by an index */
DECLSPEC H3Error H3_EXPORT(maxFaceCount)(H3Index h3, int *out);
/** @brief Find all icosahedron faces intersected by a given H3 index */
DECLSPEC H3Error H3_EXPORT(getIcosahedronFaces)(H3Index h3, int *out);
/** @} */
/** @defgroup areNeighborCells areNeighborCells
* Functions for areNeighborCells
* @{
*/
/** @brief returns whether or not the provided hexagons border */
DECLSPEC H3Error H3_EXPORT(areNeighborCells)(H3Index origin,
H3Index destination, int *out);
/** @} */
/** @defgroup cellsToDirectedEdge cellsToDirectedEdge
* Functions for cellsToDirectedEdge
* @{
*/
/** @brief returns the directed edge H3Index for the specified origin and
* destination */
DECLSPEC H3Error H3_EXPORT(cellsToDirectedEdge)(H3Index origin,
H3Index destination,
H3Index *out);
/** @} */
/** @defgroup isValidDirectedEdge isValidDirectedEdge
* Functions for isValidDirectedEdge
* @{
*/
/** @brief returns whether the H3Index is a valid directed edge */
DECLSPEC int H3_EXPORT(isValidDirectedEdge)(H3Index edge);
/** @} */
/** @defgroup getDirectedEdgeOrigin \
* getDirectedEdgeOrigin
* Functions for getDirectedEdgeOrigin
* @{
*/
/** @brief Returns the origin hexagon H3Index from the directed edge
* H3Index */
DECLSPEC H3Error H3_EXPORT(getDirectedEdgeOrigin)(H3Index edge, H3Index *out);
/** @} */
/** @defgroup getDirectedEdgeDestination \
* getDirectedEdgeDestination
* Functions for getDirectedEdgeDestination
* @{
*/
/** @brief Returns the destination hexagon H3Index from the directed edge
* H3Index */
DECLSPEC H3Error H3_EXPORT(getDirectedEdgeDestination)(H3Index edge,
H3Index *out);
/** @} */
/** @defgroup directedEdgeToCells \
* directedEdgeToCells
* Functions for directedEdgeToCells
* @{
*/
/** @brief Returns the origin and destination hexagons from the directed
* edge H3Index */
DECLSPEC H3Error H3_EXPORT(directedEdgeToCells)(H3Index edge,
H3Index *originDestination);
/** @} */
/** @defgroup originToDirectedEdges \
* originToDirectedEdges
* Functions for originToDirectedEdges
* @{
*/
/** @brief Returns the 6 (or 5 for pentagons) edges associated with the H3Index
*/
DECLSPEC H3Error H3_EXPORT(originToDirectedEdges)(H3Index origin,
H3Index *edges);
/** @} */
/** @defgroup directedEdgeToBoundary directedEdgeToBoundary
* Functions for directedEdgeToBoundary
* @{
*/
/** @brief Returns the CellBoundary containing the coordinates of the edge */
DECLSPEC H3Error H3_EXPORT(directedEdgeToBoundary)(H3Index edge,
CellBoundary *gb);
/** @} */
/** @defgroup cellToVertex cellToVertex
* Functions for cellToVertex
* @{
*/
/** @brief Returns a single vertex for a given cell, as an H3 index */
DECLSPEC H3Error H3_EXPORT(cellToVertex)(H3Index origin, int vertexNum,
H3Index *out);
/** @} */
/** @defgroup cellToVertexes cellToVertexes
* Functions for cellToVertexes
* @{
*/
/** @brief Returns all vertexes for a given cell, as H3 indexes */
DECLSPEC H3Error H3_EXPORT(cellToVertexes)(H3Index origin, H3Index *vertexes);
/** @} */
/** @defgroup vertexToLatLng vertexToLatLng
* Functions for vertexToLatLng
* @{
*/
/** @brief Returns a single vertex for a given cell, as an H3 index */
DECLSPEC H3Error H3_EXPORT(vertexToLatLng)(H3Index vertex, LatLng *point);
/** @} */
/** @defgroup isValidVertex isValidVertex
* Functions for isValidVertex
* @{
*/
/** @brief Whether the input is a valid H3 vertex */
DECLSPEC int H3_EXPORT(isValidVertex)(H3Index vertex);
/** @} */
/** @defgroup gridDistance gridDistance
* Functions for gridDistance
* @{
*/
/** @brief Returns grid distance between two indexes */
DECLSPEC H3Error H3_EXPORT(gridDistance)(H3Index origin, H3Index h3,
int64_t *distance);
/** @} */
/** @defgroup gridPathCells gridPathCells
* Functions for gridPathCells
* @{
*/
/** @brief Number of indexes in a line connecting two indexes */
DECLSPEC H3Error H3_EXPORT(gridPathCellsSize)(H3Index start, H3Index end,
int64_t *size);
/** @brief Line of h3 indexes connecting two indexes */
DECLSPEC H3Error H3_EXPORT(gridPathCells)(H3Index start, H3Index end,
H3Index *out);
/** @} */
/** @defgroup cellToLocalIj cellToLocalIj
* Functions for cellToLocalIj
* @{
*/
/** @brief Returns two dimensional coordinates for the given index */
DECLSPEC H3Error H3_EXPORT(cellToLocalIj)(H3Index origin, H3Index h3,
uint32_t mode, CoordIJ *out);
/** @} */
/** @defgroup localIjToCell localIjToCell
* Functions for localIjToCell
* @{
*/
/** @brief Returns index for the given two dimensional coordinates */
DECLSPEC H3Error H3_EXPORT(localIjToCell)(H3Index origin, const CoordIJ *ij,
uint32_t mode, H3Index *out);
/** @} */
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+193
View File
@@ -0,0 +1,193 @@
# cython: c_string_type=unicode, c_string_encoding=utf8
from cpython cimport bool
from libc.stdint cimport uint32_t, uint64_t, int64_t
ctypedef object H3str
cdef extern from 'h3api.h':
cdef int H3_VERSION_MAJOR
cdef int H3_VERSION_MINOR
cdef int H3_VERSION_PATCH
ctypedef uint64_t H3int 'H3Index'
ctypedef uint32_t H3Error
ctypedef enum H3ErrorCodes:
E_SUCCESS = 0
E_FAILED = 1
E_DOMAIN = 2
E_LATLNG_DOMAIN = 3
E_RES_DOMAIN = 4
E_CELL_INVALID = 5
E_DIR_EDGE_INVALID = 6
E_UNDIR_EDGE_INVALID = 7
E_VERTEX_INVALID = 8
E_PENTAGON = 9
E_DUPLICATE_INPUT = 10
E_NOT_NEIGHBORS = 11
E_RES_MISMATCH = 12
E_MEMORY_ALLOC = 13
E_MEMORY_BOUNDS = 14
E_OPTION_INVALID = 15
ctypedef struct LatLng:
double lat # in radians
double lng # in radians
ctypedef struct CellBoundary:
int num_verts 'numVerts'
LatLng verts[10] # MAX_CELL_BNDRY_VERTS
ctypedef struct CoordIJ:
int i
int j
ctypedef struct LinkedLatLng:
LatLng data 'vertex'
LinkedLatLng *next
# renaming these for clarity
ctypedef struct LinkedGeoLoop:
LinkedLatLng *data 'first'
LinkedLatLng *_data_last 'last' # not needed in Cython bindings
LinkedGeoLoop *next
ctypedef struct LinkedGeoPolygon:
LinkedGeoLoop *data 'first'
LinkedGeoLoop *_data_last 'last' # not needed in Cython bindings
LinkedGeoPolygon *next
ctypedef struct GeoLoop:
int numVerts
LatLng *verts
ctypedef struct GeoPolygon:
GeoLoop geoloop
int numHoles
GeoLoop *holes
int isValidCell(H3int h) nogil
int isPentagon(H3int h) nogil
int isResClassIII(H3int h) nogil
int isValidDirectedEdge(H3int edge) nogil
int isValidVertex(H3int v) nogil
double degsToRads(double degrees) nogil
double radsToDegs(double radians) nogil
int getResolution(H3int h) nogil
int getBaseCellNumber(H3int h) nogil
H3Error latLngToCell(const LatLng *g, int res, H3int *out) nogil
H3Error cellToLatLng(H3int h, LatLng *) nogil
H3Error gridDistance(H3int h1, H3int h2, int64_t *distance) nogil
H3Error cellToVertex(H3int cell, int vertexNum, H3int *out) nogil
H3Error cellToVertexes(H3int cell, H3int *vertexes) nogil
H3Error vertexToLatLng(H3int vertex, LatLng *coord) nogil
H3Error maxGridDiskSize(int k, int64_t *out) nogil # num/out/N?
H3Error gridDisk(H3int h, int k, H3int *out) nogil
H3Error cellToParent( H3int h, int parentRes, H3int *parent) nogil
H3Error cellToCenterChild(H3int h, int childRes, H3int *child) nogil
H3Error cellToChildPos(H3int child, int parentRes, int64_t *out) nogil
H3Error childPosToCell(int64_t childPos, H3int parent, int childRes, H3int *child) nogil
H3Error cellToChildrenSize(H3int h, int childRes, int64_t *num) nogil # num/out/N?
H3Error cellToChildren( H3int h, int childRes, H3int *children) nogil
H3Error compactCells(
const H3int *cells_u,
H3int *cells_c,
const int num_u
) nogil
H3Error uncompactCellsSize(
const H3int *cells_c,
const int64_t num_c,
const int res,
int64_t *num_u
) nogil
H3Error uncompactCells(
const H3int *cells_c,
const int num_c,
H3int *cells_u,
const int num_u,
const int res
) nogil
H3Error getNumCells(int res, int64_t *out) nogil
int pentagonCount() nogil
int res0CellCount() nogil
H3Error getPentagons(int res, H3int *out) nogil
H3Error getRes0Cells(H3int *out) nogil
H3Error gridPathCellsSize(H3int start, H3int end, int64_t *size) nogil
H3Error gridPathCells(H3int start, H3int end, H3int *out) nogil
H3Error getHexagonAreaAvgKm2(int res, double *out) nogil
H3Error getHexagonAreaAvgM2(int res, double *out) nogil
H3Error cellAreaRads2(H3int h, double *out) nogil
H3Error cellAreaKm2(H3int h, double *out) nogil
H3Error cellAreaM2(H3int h, double *out) nogil
H3Error maxFaceCount(H3int h, int *out) nogil
H3Error getIcosahedronFaces(H3int h3, int *out) nogil
H3Error cellToLocalIj(H3int origin, H3int h3, uint32_t mode, CoordIJ *out) nogil
H3Error localIjToCell(H3int origin, const CoordIJ *ij, uint32_t mode, H3int *out) nogil
H3Error gridDiskDistances(H3int origin, int k, H3int *out, int *distances) nogil
H3Error gridRing(H3int origin, int k, H3int *out) nogil
H3Error gridRingUnsafe(H3int origin, int k, H3int *out) nogil
H3Error areNeighborCells(H3int origin, H3int destination, int *out) nogil
H3Error cellsToDirectedEdge(H3int origin, H3int destination, H3int *out) nogil
H3Error getDirectedEdgeOrigin(H3int edge, H3int *out) nogil
H3Error getDirectedEdgeDestination(H3int edge, H3int *out) nogil
H3Error originToDirectedEdges(H3int origin, H3int *edges) nogil
# todo: directedEdgeToCells
H3Error getHexagonEdgeLengthAvgKm(int res, double *out) nogil
H3Error getHexagonEdgeLengthAvgM(int res, double *out) nogil
H3Error edgeLengthRads(H3int edge, double *out) nogil
H3Error edgeLengthKm(H3int edge, double *out) nogil
H3Error edgeLengthM(H3int edge, double *out) nogil
H3Error cellToBoundary(H3int h3, CellBoundary *gp) nogil
H3Error directedEdgeToBoundary(H3int edge, CellBoundary *gb) nogil
double greatCircleDistanceRads(const LatLng *a, const LatLng *b) nogil
double greatCircleDistanceKm(const LatLng *a, const LatLng *b) nogil
double greatCircleDistanceM(const LatLng *a, const LatLng *b) nogil
H3Error cellsToLinkedMultiPolygon(const H3int *h3Set, const int numCells, LinkedGeoPolygon *out)
void destroyLinkedMultiPolygon(LinkedGeoPolygon *polygon)
H3Error maxPolygonToCellsSize(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t *count)
H3Error polygonToCells(const GeoPolygon *geoPolygon, int res, uint32_t flags, H3int *out)
H3Error maxPolygonToCellsSizeExperimental(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t *count)
H3Error polygonToCellsExperimental(const GeoPolygon *geoPolygon, int res, uint32_t flags, uint64_t sz, H3int *out)
# ctypedef struct GeoMultiPolygon:
# int numPolygons
# GeoPolygon *polygons
# int hexRange(H3int origin, int k, H3int *out)
# int hexRangeDistances(H3int origin, int k, H3int *out, int *distances)
# int hexRanges(H3int *h3Set, int length, int k, H3int *out)
# void h3SetToLinkedGeo(const H3int *h3Set, const int numCells, LinkedGeoPolygon *out)
# void destroyLinkedPolygon(LinkedGeoPolygon *polygon)
# H3int stringToH3(const char *str)
# void h3ToString(H3int h, char *str, size_t sz)
# void getH3intesFromUnidirectionalEdge(H3int edge, H3int *originDestination)
+7
View File
@@ -0,0 +1,7 @@
from .h3lib cimport H3int
cpdef H3int latlng_to_cell(double lat, double lng, int res) except 1
cpdef (double, double) cell_to_latlng(H3int h) except *
cpdef double great_circle_distance(
double lat1, double lng1,
double lat2, double lng2, unit=*) except -1
+325
View File
@@ -0,0 +1,325 @@
from libc.stdint cimport uint64_t
cimport h3lib
from h3lib cimport bool, H3int
from .util cimport (
check_cell,
check_edge,
check_res,
deg2coord,
coord2deg
)
from .error_system cimport check_for_error
from .memory cimport H3MemoryManager
# TODO: We might be OK with taking the GIL for the functions in this module
from libc.stdlib cimport (
# malloc as h3_malloc, # not used
calloc as h3_calloc,
realloc as h3_realloc,
free as h3_free,
)
cpdef H3int latlng_to_cell(double lat, double lng, int res) except 1:
cdef:
h3lib.LatLng c
H3int out
c = deg2coord(lat, lng)
check_for_error(
h3lib.latLngToCell(&c, res, &out)
)
return out
cpdef (double, double) cell_to_latlng(H3int h) except *:
"""Map an H3 cell into its centroid geo-coordinate (lat/lng)"""
cdef:
h3lib.LatLng c
check_cell(h)
# todo: think about: if you give this an invalid cell, should it still return a lat/lng?
# idea: safe and unsafe APIs?
check_for_error(
h3lib.cellToLatLng(h, &c)
)
return coord2deg(c)
cdef h3lib.GeoLoop make_geoloop(latlngs) except *:
"""
The returned `GeoLoop` must be freed with a call to `free_geoloop`.
Parameters
----------
latlngs : list or tuple
GeoLoop: A sequence of >= 3 (lat, lng) pairs where the last
element may or may not be same as the first (to form a closed loop).
The order of the pairs may be either clockwise or counterclockwise.
"""
cdef:
h3lib.GeoLoop gl
gl.numVerts = len(latlngs)
# todo: need for memory management
# can automatically free?
gl.verts = <h3lib.LatLng*> h3_calloc(gl.numVerts, sizeof(h3lib.LatLng))
for i, (lat, lng) in enumerate(latlngs):
gl.verts[i] = deg2coord(lat, lng)
return gl
cdef free_geoloop(h3lib.GeoLoop* gl):
h3_free(gl.verts)
gl.verts = NULL
cdef class GeoPolygon:
cdef:
h3lib.GeoPolygon gp
def __cinit__(self, outer, holes=None):
"""
Parameters
----------
outer : list or tuple
GeoLoop
A GeoLoop is a sequence of >= 3 (lat, lng) pairs where the last
element may or may not be same as the first (to form a closed loop).
The order of the pairs may be either clockwise or counterclockwise.
holes : list or tuple
A sequence of GeoLoops
"""
if holes is None:
holes = []
self.gp.geoloop = make_geoloop(outer)
self.gp.numHoles = len(holes)
self.gp.holes = NULL
if len(holes) > 0:
self.gp.holes = <h3lib.GeoLoop*> h3_calloc(len(holes), sizeof(h3lib.GeoLoop))
for i, hole in enumerate(holes):
self.gp.holes[i] = make_geoloop(hole)
def __dealloc__(self):
free_geoloop(&self.gp.geoloop)
for i in range(self.gp.numHoles):
free_geoloop(&self.gp.holes[i])
h3_free(self.gp.holes)
def polygon_to_cells(outer, int res, holes=None):
""" Get the set of cells whose center is contained in a polygon.
The polygon is defined similarity to the GeoJson standard, with an exterior
`outer` ring of lat/lng points, and a list of `holes`, each of which are also
rings of lat/lng points.
Each ring may be in clockwise or counter-clockwise order
(right-hand rule or not), and may or may not be a closed loop (where the last
element is equal to the first).
The GeoJSON spec requires the right-hand rule and a closed loop, but
this function relaxes those constraints.
Unlike the GeoJson standard, the elements of the lat/lng pairs of each
ring are in lat/lng order, instead of lng/lat order.
We'll handle translation to different formats in the Python code,
rather than the Cython code.
Parameters
----------
outer : list or tuple
A ring given by a sequence of lat/lng pairs.
res : int
The resolution of the output hexagons
holes : list or tuple
A collection of rings, each given by a sequence of lat/lng pairs.
These describe any the "holes" in the polygon.
"""
cdef:
uint64_t n
check_res(res)
if not outer:
return H3MemoryManager(0).to_mv()
gp = GeoPolygon(outer, holes=holes)
check_for_error(
h3lib.maxPolygonToCellsSize(&gp.gp, res, 0, &n)
)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.polygonToCells(&gp.gp, res, 0, hmm.ptr)
)
mv = hmm.to_mv()
return mv
def polygons_to_cells(polygons, int res):
mvs = [
polygon_to_cells(outer=poly.outer, res=res, holes=poly.holes)
for poly in polygons
]
n = sum(map(len, mvs))
hmm = H3MemoryManager(n)
# probably super inefficient, but it is working!
# tood: move this to C
k = 0
for mv in mvs:
for v in mv:
hmm.ptr[k] = v
k += 1
return hmm.to_mv()
def polygon_to_cells_experimental(outer, int res, int flag, holes=None):
""" Get the set of cells whose center is contained in a polygon.
The polygon is defined similarity to the GeoJson standard, with an exterior
`outer` ring of lat/lng points, and a list of `holes`, each of which are also
rings of lat/lng points.
Each ring may be in clockwise or counter-clockwise order
(right-hand rule or not), and may or may not be a closed loop (where the last
element is equal to the first).
The GeoJSON spec requires the right-hand rule and a closed loop, but
this function relaxes those constraints.
Unlike the GeoJson standard, the elements of the lat/lng pairs of each
ring are in lat/lng order, instead of lng/lat order.
We'll handle translation to different formats in the Python code,
rather than the Cython code.
Parameters
----------
outer : list or tuple
A ring given by a sequence of lat/lng pairs.
res : int
The resolution of the output hexagons
flag : int
Polygon to cells flag, such as containment mode.
holes : list or tuple
A collection of rings, each given by a sequence of lat/lng pairs.
These describe any the "holes" in the polygon.
"""
cdef:
uint64_t n
check_res(res)
if not outer:
return H3MemoryManager(0).to_mv()
gp = GeoPolygon(outer, holes=holes)
check_for_error(
h3lib.maxPolygonToCellsSizeExperimental(&gp.gp, res, flag, &n)
)
hmm = H3MemoryManager(n)
check_for_error(
h3lib.polygonToCellsExperimental(&gp.gp, res, flag, n, hmm.ptr)
)
mv = hmm.to_mv()
return mv
def polygons_to_cells_experimental(polygons, int res, int flag):
mvs = [
polygon_to_cells_experimental(outer=poly.outer, res=res, holes=poly.holes, flag=flag)
for poly in polygons
]
n = sum(map(len, mvs))
hmm = H3MemoryManager(n)
# probably super inefficient, but it is working!
# tood: move this to C
k = 0
for mv in mvs:
for v in mv:
hmm.ptr[k] = v
k += 1
return hmm.to_mv()
def cell_to_boundary(H3int h):
"""Compose an array of geo-coordinates that outlines a hexagonal cell"""
cdef:
h3lib.CellBoundary gb
check_cell(h)
h3lib.cellToBoundary(h, &gb)
verts = tuple(
coord2deg(gb.verts[i])
for i in range(gb.num_verts)
)
return verts
def directed_edge_to_boundary(H3int edge):
""" Returns the CellBoundary containing the coordinates of the edge
"""
cdef:
h3lib.CellBoundary gb
check_edge(edge)
h3lib.directedEdgeToBoundary(edge, &gb)
# todo: move this verts transform into the CellBoundary object
verts = tuple(
coord2deg(gb.verts[i])
for i in range(gb.num_verts)
)
return verts
cpdef double great_circle_distance(
double lat1, double lng1,
double lat2, double lng2, unit='km') except -1:
a = deg2coord(lat1, lng1)
b = deg2coord(lat2, lng2)
if unit == 'rads':
d = h3lib.greatCircleDistanceRads(&a, &b)
elif unit == 'km':
d = h3lib.greatCircleDistanceKm(&a, &b)
elif unit == 'm':
d = h3lib.greatCircleDistanceM(&a, &b)
else:
raise ValueError('Unknown unit: {}'.format(unit))
return d
+12
View File
@@ -0,0 +1,12 @@
from .h3lib cimport H3int
cdef class H3MemoryManager:
cdef:
size_t n
H3int* ptr
cdef H3int[:] to_mv(self)
cdef H3int[:] to_mv_keep_zeros(self)
cdef int[:] int_mv(size_t n)
cpdef H3int[:] iter_to_mv(cells)
+248
View File
@@ -0,0 +1,248 @@
from cython.view cimport array
from .h3lib cimport H3int
"""
### Memory allocation options
We have a few options for the memory allocation functions.
There's a trade-off between using the Python allocators which let Python
track memory usage and offers some optimizations vs the system
allocators, which do not need to acquire the GIL.
"""
"""
System allocation functions. These do not acquire the GIL.
"""
from libc.stdlib cimport (
# malloc as h3_malloc, # not used
calloc as h3_calloc,
realloc as h3_realloc,
free as h3_free,
)
"""
PyMem_Raw* functions should just be wrappers around system allocators
also given in libc.stdlib. These functions do not acquire the GIL.
Note that these do not have a calloc function until py 3.5 and Cython 3.0,
so we would need to zero-out memory manually.
https://python.readthedocs.io/en/stable/c-api/memory.html#raw-memory-interface
"""
# from cpython.mem cimport (
# PyMem_RawMalloc as h3_malloc,
# # PyMem_RawCalloc as h3_calloc, # only in Python >=3.5 (and Cython >=3.0?)
# PyMem_RawRealloc as h3_realloc,
# PyMem_RawFree as h3_free,
# )
"""
These functions use the Python allocator (instead of the system allocator),
which offers some optimizations for Python, and allows Python to track
memory usage. However, these functions must acquire the GIL.
Note that these do not have a calloc function until py 3.5 and Cython 3.0,
so we would need to zero-out memory manually.
https://cython.readthedocs.io/en/stable/src/tutorial/memory_allocation.html
https://python.readthedocs.io/en/stable/c-api/memory.html#memory-interface
"""
# from cpython.mem cimport (
# PyMem_Malloc as h3_malloc,
# # PyMem_Calloc as h3_calloc, # only in Python >=3.5 (and Cython >=3.0?)
# PyMem_Realloc as h3_realloc,
# PyMem_Free as h3_free,
# )
cdef size_t move_nonzeros(H3int* a, size_t n):
""" Move nonzero elements to front of array `a` of length `n`.
Return the number of nonzero elements.
Loop invariant: Everything *before* `i` or *after* `j` is "done".
Move `i` and `j` inwards until they equal, and exit.
You can move `i` forward until there's a zero in front of it.
You can move `j` backward until there's a nonzero to the left of it.
Anything to the right of `j` is "junk" that can be reallocated.
| a | b | 0 | c | d | ... |
^ ^
i j
| a | b | d | c | d | ... |
^ ^
i j
"""
cdef:
size_t i = 0
size_t j = n
while i < j:
if a[j-1] == 0:
j -= 1
continue
if a[i] != 0:
i += 1
continue
# if we're here, we know:
# a[i] == 0
# a[j-1] != 0
# i < j
# so we can swap! (actually, move a[j-1] -> a[i])
a[i] = a[j-1]
j -= 1
return i
cdef H3int[:] empty_memory_view():
# todo: get rid of this?
# there's gotta be a better way to do this...
# create an empty cython.view.array?
cdef:
H3int a[1]
return (<H3int[:]>a)[:0]
cdef _remove_zeros(H3MemoryManager x):
x.n = move_nonzeros(x.ptr, x.n)
if x.n == 0:
h3_free(x.ptr)
x.ptr = NULL
else:
x.ptr = <H3int*> h3_realloc(x.ptr, x.n*sizeof(H3int))
if not x.ptr:
raise MemoryError()
cdef H3int[:] _copy_to_mv(const H3int* ptr, size_t n):
cdef:
array arr
arr = <H3int[:n]> ptr
arr.callback_free_data = h3_free
return arr
cdef H3int[:] _create_mv(H3MemoryManager x):
if x.n == 0:
h3_free(x.ptr)
x.ptr = NULL
mv = empty_memory_view()
else:
mv = _copy_to_mv(x.ptr, x.n)
# responsibility for the memory moves from this object to the array/memoryview
x.ptr = NULL
x.n = 0
return mv
"""
TODO: The not None declaration for the argument automatically rejects None values as input, which would otherwise be allowed. The reason why None is allowed by default is that it is conveniently used for return arguments:
https://cython.readthedocs.io/en/latest/src/userguide/memoryviews.html#syntax
TODO: potential optimization: https://cython.readthedocs.io/en/latest/src/userguide/memoryviews.html#performance-disabling-initialization-checks
## future improvements:
- abolish any appearance of &thing[0]. (i.e., identical interfaces)
- can i make the interface for all these memory views identical?
"""
cdef class H3MemoryManager:
"""
Cython object in charge of allocating and freeing memory for arrays
of H3 indexes.
Initially allocates memory and provides access through `self.ptr` and
`self.n`.
The `to_mv()` function removes responsibility for the allocated memory
from this object to a memory view object. A memory view object automatically
deallocates its memory during garbage collection.
If the H3MemoryManager is garbage collected before running `to_mv()`,
it will deallocate its memory itself.
This pattern is useful for a few reasons:
- provide convenient access to the raw memory pointer and length for passing
to h3lib functions
- remove zeroes from the array output (some h3lib functions may return
results with zeros/H3NULL values)
- cython and python array types have weird interfaces; memoryviews are
much cleaner
If we find a better way to do these then this class may no longer be
necessary.
TODO: consider a context manager pattern
"""
def __cinit__(self, size_t n):
self.n = n
self.ptr = <H3int*> h3_calloc(self.n, sizeof(H3int))
if not self.ptr:
raise MemoryError()
cdef H3int[:] to_mv_keep_zeros(self):
# todo: this could be a private method
return _create_mv(self)
cdef H3int[:] to_mv(self):
_remove_zeros(self)
return _create_mv(self)
def __dealloc__(self):
# If the memory has been handed off to a memoryview, this pointer
# should be NULL, and deallocing on NULL is fine.
# If the pointer is *not* NULL, then this means the MemoryManager
# has is still responsible for the memory (it hasn't given the memory away to another object).
h3_free(self.ptr)
"""
todo: combine with the H3MemoryManager using fused types?
https://cython.readthedocs.io/en/stable/src/userguide/fusedtypes.html
"""
cdef int[:] int_mv(size_t n):
cdef:
array arr
if n == 0:
raise MemoryError()
else:
ptr = <int*> h3_calloc(n, sizeof(int))
if ptr is NULL:
raise MemoryError()
arr = <int[:n]> ptr
arr.callback_free_data = h3_free
return arr
cpdef H3int[:] iter_to_mv(cells):
""" cells needs to be an iterable that knows its size...
or should we have it match the np.fromiter function, which infers if not available?
"""
cdef:
H3int[:] mv
n = len(cells)
mv = H3MemoryManager(n).to_mv_keep_zeros()
for i,h in enumerate(cells):
mv[i] = h
return mv
+60
View File
@@ -0,0 +1,60 @@
cimport h3lib
from h3lib cimport H3int
from .util cimport check_cell, coord2deg
# todo: it's driving me crazy that these three functions are all essentially the same linked list walker...
# grumble: no way to do iterators in with cdef functions!
cdef walk_polys(const h3lib.LinkedGeoPolygon* L):
out = []
while L:
out += [walk_loops(L.data)]
L = L.next
return out
cdef walk_loops(const h3lib.LinkedGeoLoop* L):
out = []
while L:
out += [walk_coords(L.data)]
L = L.next
return out
cdef walk_coords(const h3lib.LinkedLatLng* L):
out = []
while L:
out += [coord2deg(L.data)]
L = L.next
return out
# todo: tuples instead of lists?
def _to_multi_polygon(const H3int[:] cells):
cdef:
h3lib.LinkedGeoPolygon polygon
for h in cells:
check_cell(h)
h3lib.cellsToLinkedMultiPolygon(&cells[0], len(cells), &polygon)
out = walk_polys(&polygon)
# we're still responsible for cleaning up the passed in `polygon`,
# but not a problem here, since it is stack allocated
h3lib.destroyLinkedMultiPolygon(&polygon)
return out
def cells_to_multi_polygon(const H3int[:] cells):
# todo: gotta be a more elegant way to handle these...
if len(cells) == 0:
return []
multipoly = _to_multi_polygon(cells)
return multipoly
+13
View File
@@ -0,0 +1,13 @@
from .h3lib cimport H3int, H3str, LatLng
cdef LatLng deg2coord(double lat, double lng) nogil
cdef (double, double) coord2deg(LatLng c) nogil
cpdef H3int str_to_int(H3str h) except? 0
cpdef H3str int_to_str(H3int x)
cdef check_cell(H3int h)
cdef check_edge(H3int e)
cdef check_res(int res)
cdef check_vertex(H3int v)
cdef check_distance(int k)
+89
View File
@@ -0,0 +1,89 @@
from .h3lib cimport H3int, H3str, isValidCell, isValidDirectedEdge, isValidVertex
cimport h3lib
from .error_system import (
H3ResDomainError,
H3DomainError,
H3DirEdgeInvalidError,
H3CellInvalidError,
H3VertexInvalidError
)
cdef h3lib.LatLng deg2coord(double lat, double lng) nogil:
cdef:
h3lib.LatLng c
c.lat = h3lib.degsToRads(lat)
c.lng = h3lib.degsToRads(lng)
return c
cdef (double, double) coord2deg(h3lib.LatLng c) nogil:
return (
h3lib.radsToDegs(c.lat),
h3lib.radsToDegs(c.lng)
)
cpdef basestring c_version():
v = (
h3lib.H3_VERSION_MAJOR,
h3lib.H3_VERSION_MINOR,
h3lib.H3_VERSION_PATCH,
)
return '{}.{}.{}'.format(*v)
cpdef H3int str_to_int(H3str h) except? 0:
return int(h, 16)
cpdef H3str int_to_str(H3int x):
""" Convert H3 integer to hex string representation
Need to be careful in Python 2 because `hex(x)` may return a string
with a trailing `L` character (denoting a "large" integer).
The formatting approach below avoids this.
Also need to be careful about unicode/str differences.
"""
return '{:x}'.format(x)
cdef check_cell(H3int h):
""" Check if valid H3 "cell" (hexagon or pentagon).
Does not check if a valid H3 edge, for example.
Since this function is used by multiple interfaces (int or str),
we want the error message to be informative to the user
in either case.
We use the builtin `hex` function instead of `int_to_str` to
prepend `0x` to indicate that this **integer** representation
is incorrect, but in a format that is easily compared to
`str` inputs.
"""
if isValidCell(h) == 0:
raise H3CellInvalidError('Integer is not a valid H3 cell: {}'.format(hex(h)))
cdef check_edge(H3int e):
if isValidDirectedEdge(e) == 0:
raise H3DirEdgeInvalidError('Integer is not a valid H3 edge: {}'.format(hex(e)))
cdef check_vertex(H3int v):
if isValidVertex(v) == 0:
raise H3VertexInvalidError('Integer is not a valid H3 vertex: {}'.format(hex(v)))
cdef check_res(int res):
if (res < 0) or (res > 15):
raise H3ResDomainError(res)
cdef check_distance(int k):
if k < 0:
raise H3DomainError(
'Grid distances must be nonnegative. Received: {}'.format(k)
)
+6
View File
@@ -0,0 +1,6 @@
from .h3lib cimport bool, H3int
cpdef H3int cell_to_vertex(H3int h, int vertex_num) except 1
cpdef H3int[:] cell_to_vertexes(H3int h)
cpdef (double, double) vertex_to_latlng(H3int v) except *
cpdef bool is_valid_vertex(H3int v)
+54
View File
@@ -0,0 +1,54 @@
cimport h3lib
from h3lib cimport bool, H3int
from .util cimport (
check_cell,
check_vertex,
coord2deg
)
from .error_system cimport check_for_error
from .memory cimport H3MemoryManager
cpdef H3int cell_to_vertex(H3int h, int vertex_num) except 1:
cdef:
H3int out
check_cell(h)
check_for_error(
h3lib.cellToVertex(h, vertex_num, &out)
)
return out
cpdef H3int[:] cell_to_vertexes(H3int h):
cdef:
H3int out
check_cell(h)
hmm = H3MemoryManager(6)
check_for_error(
h3lib.cellToVertexes(h, hmm.ptr)
)
mv = hmm.to_mv()
return mv
cpdef (double, double) vertex_to_latlng(H3int v) except *:
cdef:
h3lib.LatLng c
check_vertex(v)
check_for_error(
h3lib.vertexToLatLng(v, &c)
)
return coord2deg(c)
cpdef bool is_valid_vertex(H3int v):
return h3lib.isValidVertex(v) == 1
+338
View File
@@ -0,0 +1,338 @@
from abc import ABCMeta, abstractmethod
class H3Shape(metaclass=ABCMeta):
"""
Abstract parent class of ``LatLngPoly`` and ``LatLngMultiPoly``.
"""
@property
@abstractmethod
def __geo_interface__(self):
""" https://github.com/pytest-dev/pytest-cov/issues/428 """
class LatLngPoly(H3Shape):
"""
Container for loops of lat/lng points describing a polygon, possibly with holes.
Attributes
----------
outer : list[tuple[float, float]]
List of lat/lng points describing the outer loop of the polygon
holes : list[list[tuple[float, float]]]
List of loops of lat/lng points describing the holes of the polygon
Examples
--------
A polygon with a single outer ring consisting of 4 points, having no holes:
>>> LatLngPoly(
... [(37.68, -122.54), (37.68, -122.34), (37.82, -122.34), (37.82, -122.54)],
... )
<LatLngPoly: [4]>
The same polygon, but with one hole consisting of 3 points:
>>> LatLngPoly(
... [(37.68, -122.54), (37.68, -122.34), (37.82, -122.34), (37.82, -122.54)],
... [(37.76, -122.51), (37.76, -122.44), (37.81, -122.51)],
... )
<LatLngPoly: [4/(3,)]>
The same as above, but with one additional hole, made up of 5 points:
>>> LatLngPoly(
... [(37.68, -122.54), (37.68, -122.34), (37.82, -122.34), (37.82, -122.54)],
... [(37.76, -122.51), (37.76, -122.44), (37.81, -122.51)],
... [(37.71, -122.43), (37.71, -122.37), (37.73, -122.37), (37.75, -122.41),
... (37.73, -122.43)],
... )
<LatLngPoly: [4/(3, 5)]>
"""
def __init__(self, outer, *holes):
loops = [outer] + list(holes)
for loop in loops:
if len(loop) in (1, 2):
raise ValueError('Non-empty LatLngPoly loops need at least 3 points.')
point_dimensions = set(map(len, loop))
# empty set is possible for empty polygons, so we check if a subset
if not (point_dimensions <= {2}):
raise ValueError('LatLngPoly only accepts 2D points: lat/lng.')
self.outer = tuple(_open_ring(outer))
self.holes = tuple(
_open_ring(hole)
for hole in holes
)
def __repr__(self):
return '<LatLngPoly: {}>'.format(self.loopcode)
def __len__(self):
"""
Should this be the number of points in the outer loop,
the number of holes (or +1 for the outer loop)?
"""
raise NotImplementedError('No clear definition of length for LatLngPoly.')
@property
def loopcode(self):
""" Short code for describing the length of the outer loop and each hole
Example: ``[382/(18, 6, 6)]`` indicates an outer loop of 382 points,
along with 3 holes with 18, 6, and 6 points, respectively.
Example: ``[15]`` indicates an outer loop of 15 points and no holes.
"""
outer = len(self.outer)
holes = tuple(map(len, self.holes))
outer = str(outer)
if holes:
out = outer + '/' + str(holes)
else:
out = outer
return '[' + out + ']'
@property
def __geo_interface__(self):
ll2 = _polygon_to_LL2(self)
gj_dict = _LL2_to_geojson_dict(ll2)
return gj_dict
class LatLngMultiPoly(H3Shape):
"""
Container for multiple ``LatLngPoly`` polygons.
Attributes
----------
polys : list[LatLngPoly]
List of lat/lng points describing the outer loop of the polygon
"""
def __init__(self, *polys):
self.polys = tuple(polys)
for p in self.polys:
if not isinstance(p, LatLngPoly):
raise ValueError('LatLngMultiPoly requires each input to be an LatLngPoly object, instead got: ' + str(p)) # noqa
def __repr__(self):
out = [p.loopcode for p in self.polys]
out = ', '.join(out)
out = '<LatLngMultiPoly: {}>'.format(out)
return out
def __iter__(self):
return iter(self.polys)
def __len__(self):
""" Give the number of polygons in this multi-polygon.
"""
"""
TODO: Pandas series or dataframe representation changes depending
on if __len__ is defined.
I'd prefer the one that states `LatLngMultiPoly`.
It seems like Pandas is assuming an iterable is best-described
by its elements when choosing the representation.
when __len__ *IS NOT* defined:
0 <LatLngMultiPoly: [368], [20], [6]>
1 <LatLngMultiPoly: [632/(6, 6, 6, 6, 6)], [290/(6,)...
2 <LatLngMultiPoly: [490/(6, 6, 10, 10, 14, 10, 6)],...
3 <LatLngMultiPoly: [344/(6,)], [22], [6], [10], [6]...
4 <LatLngMultiPoly: [382/(18, 6, 6)], [32], [6], [18...
when __len__ *IS* defined:
0 (<LatLngPoly: [368]>, <LatLngPoly: [20]>, <LatLngPoly: [6]>)
1 (<LatLngPoly: [632/(6, 6, 6, 6, 6)]>, <LatLngPoly: [29...
2 (<LatLngPoly: [490/(6, 6, 10, 10, 14, 10, 6)]>, <H...
3 (<LatLngPoly: [344/(6,)]>, <LatLngPoly: [22]>, <LatLngPoly...
4 (<LatLngPoly: [382/(18, 6, 6)]>, <LatLngPoly: [32]>, <...
"""
return len(self.polys)
def __getitem__(self, index):
return self.polys[index]
@property
def __geo_interface__(self):
ll3 = _mpoly_to_LL3(self)
gj_dict = _LL3_to_geojson_dict(ll3)
return gj_dict
"""
Helpers for cells_to_geojson and geojson_to_cells.
Dealing with GeoJSON Polygons and MultiPolygons can be confusing because
there are so many nested lists. To help keep track, we use the following
symbols to denote different levels of nesting.
LL0: lat/lng or lng/lat pair
LL1: list of LL0s
LL2: list of LL1s (i.e., a polygon with holes)
LL3: list of LL2s (i.e., several polygons with holes)
## TODO
- Allow user to specify "container" in `cells_to_geojson`.
- That is, they may want a MultiPolygon even if the output fits in a Polygon
- 'auto', Polygon, MultiPolygon, FeatureCollection, GeometryCollection, ...
"""
def _mpoly_to_LL3(mpoly):
ll3 = tuple(
_polygon_to_LL2(poly)
for poly in mpoly
)
return ll3
def _LL3_to_mpoly(ll3):
polys = [
_LL2_to_polygon(ll2)
for ll2 in ll3
]
mpoly = LatLngMultiPoly(*polys)
return mpoly
def _polygon_to_LL2(poly):
ll2 = [poly.outer] + list(poly.holes)
ll2 = tuple(
_close_ring(_swap_latlng(ll1))
for ll1 in ll2
)
return ll2
def _remove_z(ll1):
ll1 = [(a, b) for a, b, *z in ll1]
return ll1
def _LL2_to_polygon(ll2):
ll2 = [
_remove_z(ll1)
for ll1 in ll2
]
ll2 = [
_swap_latlng(ll1)
for ll1 in ll2
]
h3poly = LatLngPoly(*ll2)
return h3poly
def _LL2_to_geojson_dict(ll2):
gj_dict = {
'type': 'Polygon',
'coordinates': ll2,
}
return gj_dict
def _LL3_to_geojson_dict(ll3):
gj_dict = {
'type': 'MultiPolygon',
'coordinates': ll3,
}
return gj_dict
def _swap_latlng(ll1):
ll1 = tuple(
(b, a) for a, b in ll1
)
return ll1
def _close_ring(ll1):
"""
Idempotent
"""
if ll1 and (ll1[0] != ll1[-1]):
ll1 = tuple(ll1) + (ll1[0],)
return ll1
def _open_ring(ll1):
"""
Idempotent
"""
if ll1 and (ll1[0] == ll1[-1]):
ll1 = ll1[:-1]
return ll1
def geo_to_h3shape(geo):
"""
Translate from ``__geo_interface__`` to H3Shape.
``geo`` either implements ``__geo_interface__`` or is a dict matching the format
Returns
-------
H3Shape
"""
# geo can be dict, a __geo_interface__, a string, LatLngPoly or LatLngMultiPoly
if isinstance(geo, H3Shape):
return geo
if hasattr(geo, '__geo_interface__'):
# get dict
geo = geo.__geo_interface__
assert isinstance(geo, dict) # todo: remove
t = geo['type']
coord = geo['coordinates']
if t == 'Polygon':
ll2 = coord
shape = _LL2_to_polygon(ll2)
elif t == 'MultiPolygon':
ll3 = coord
shape = _LL3_to_mpoly(ll3)
else:
raise ValueError('Unrecognized type: ' + str(t))
return shape
def h3shape_to_geo(h3shape):
"""
Translate from an ``H3Shape`` to a ``__geo_interface__`` dict.
``h3shape`` should be either ``LatLngPoly`` or ``LatLngMultiPoly``
Returns
-------
dict
"""
return h3shape.__geo_interface__
+3
View File
@@ -0,0 +1,3 @@
from importlib import metadata
__version__ = metadata.version(__package__ or __name__)
+6
View File
@@ -0,0 +1,6 @@
# flake8: noqa
from . import basic_int
from . import basic_str
from . import memview_int
from . import numpy_int
File diff suppressed because it is too large Load Diff
+17
View File
@@ -0,0 +1,17 @@
from ... import _cy
def _in_scalar(x):
return x
_out_scalar = _in_scalar
def _in_collection(cells):
it = list(cells)
return _cy.iter_to_mv(it)
_out_collection = list
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
from ... import _cy
_in_scalar = _cy.str_to_int
_out_scalar = _cy.int_to_str
def _in_collection(cells):
it = [_cy.str_to_int(h) for h in cells]
return _cy.iter_to_mv(it)
def _out_collection(mv):
return list(_cy.int_to_str(h) for h in mv)
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
def _id(x):
return x
_in_scalar = _id
_out_scalar = _id
_in_collection = _id
_out_collection = _id
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
def _in_scalar(x):
return x
_out_scalar = _in_scalar
def _in_collection(x):
import numpy as np
# array is copied only if dtype does not match
# `list`s should work, but not `set`s of integers
return np.asarray(x, dtype='uint64')
_out_collection = _in_collection
@@ -1 +0,0 @@
pip
-180
View File
@@ -1,180 +0,0 @@
Metadata-Version: 2.4
Name: reactivex
Version: 4.1.0
Summary: ReactiveX (Rx) for Python
License: MIT
License-File: LICENSE
Author: Dag Brattli
Author-email: dag@brattli.net
Requires-Python: >=3.8,<4.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Other Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Dist: typing-extensions (>=4.1.1,<5.0.0)
Project-URL: Documentation, https://rxpy.readthedocs.io/en/latest/
Project-URL: Homepage, http://reactivex.io
Project-URL: Repository, https://github.com/ReactiveX/RxPY
Description-Content-Type: text/x-rst
===============================
The ReactiveX for Python (RxPY)
===============================
.. image:: https://github.com/ReactiveX/RxPY/workflows/Python%20package/badge.svg
:target: https://github.com/ReactiveX/RxPY/actions
:alt: Build Status
.. image:: https://img.shields.io/coveralls/ReactiveX/RxPY.svg
:target: https://coveralls.io/github/ReactiveX/RxPY
:alt: Coverage Status
.. image:: https://img.shields.io/pypi/v/reactivex.svg
:target: https://pypi.org/project/reactivex/
:alt: PyPY Package Version
.. image:: https://img.shields.io/readthedocs/rxpy.svg
:target: https://readthedocs.org/projects/rxpy/builds/
:alt: Documentation Status
*A library for composing asynchronous and event-based programs using observable
collections and query operator functions in Python*
ReactiveX for Python v4
-----------------------
For v3.X please go to the `v3 branch
<https://github.com/ReactiveX/RxPY/tree/release/v3.2.x>`_.
ReactiveX for Python v4.x runs on `Python <http://www.python.org/>`_ 3.9 or above. To
install:
.. code:: console
pip3 install reactivex
About ReactiveX
---------------
ReactiveX for Python (RxPY) is a library for composing asynchronous and event-based
programs using observable sequences and pipable query operators in Python. Using Rx,
developers represent asynchronous data streams with Observables, query asynchronous data
streams using operators, and parameterize concurrency in data/event streams using
Schedulers.
.. code:: python
import reactivex as rx
from reactivex import operators as ops
source = rx.of("Alpha", "Beta", "Gamma", "Delta", "Epsilon")
composed = source.pipe(
ops.map(lambda s: len(s)),
ops.filter(lambda i: i >= 5)
)
composed.subscribe(lambda value: print("Received {0}".format(value)))
Learning ReactiveX
------------------
Read the `documentation
<https://rxpy.readthedocs.io/en/latest/>`_ to learn
the principles of ReactiveX and get the complete reference of the available
operators.
If you need to migrate code from RxPY v1.x or v3.x, read the `migration
<https://rxpy.readthedocs.io/en/latest/migration.html>`_ section.
There is also a list of third party documentation available `here
<https://rxpy.readthedocs.io/en/latest/additional_reading.html>`_.
Community
----------
Join the conversation on GitHub `Discussions
<https://github.com/ReactiveX/RxPY/discussions>`_! if you have any questions or
suggestions.
Differences from .NET and RxJS
------------------------------
ReactiveX for Python is a fairly complete implementation of
`Rx <http://reactivex.io/>`_ with more than
`120 operators <https://rxpy.readthedocs.io/en/latest/operators.html>`_, and
over `1300 passing unit-tests <https://coveralls.io/github/ReactiveX/RxPY>`_. RxPY
is mostly a direct port of RxJS, but also borrows a bit from Rx.NET and RxJava in
terms of threading and blocking operators.
ReactiveX for Python follows `PEP 8 <http://legacy.python.org/dev/peps/pep-0008/>`_, so
all function and method names are ``snake_cased`` i.e lowercase with words separated by
underscores as necessary to improve readability.
Thus .NET code such as:
.. code:: c#
var group = source.GroupBy(i => i % 3);
need to be written with an ``_`` in Python:
.. code:: python
group = source.pipe(ops.group_by(lambda i: i % 3))
With ReactiveX for Python you should use `named keyword arguments
<https://docs.python.org/3/glossary.html>`_ instead of positional arguments when an
operator has multiple optional arguments. RxPY will not try to detect which arguments
you are giving to the operator (or not).
Development
-----------
This project is managed using `Poetry <https://python-poetry.org/>`_. Code is formatted
using `Black <https://github.com/psf/black>`_, `isort
<https://github.com/PyCQA/isort>`_. Code is statically type checked using `pyright
<https://github.com/microsoft/pyright>`_ and `mypy <http://mypy-lang.org/>`_.
If you want to take advantage of the default VSCode integration, then
first configure Poetry to make its virtual environment in the
repository:
.. code:: console
poetry config virtualenvs.in-project true
After cloning the repository, activate the tooling:
.. code:: console
poetry install
poetry run pre-commit install
Run unit tests:
.. code:: console
poetry run pytest
Run code checks (manually):
.. code:: console
poetry run pre-commit run --all-files
-225
View File
@@ -1,225 +0,0 @@
reactivex-4.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
reactivex-4.1.0.dist-info/METADATA,sha256=rSqPVN97BAmfb3t-XajHhZYG_BsViZQqFQsJaF3jXsc,5697
reactivex-4.1.0.dist-info/RECORD,,
reactivex-4.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
reactivex-4.1.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
reactivex-4.1.0.dist-info/licenses/LICENSE,sha256=vModcyjYiECG6tvSqOZvENUzjfLXk0FeVtBS9pUy_zE,1112
reactivex/__init__.py,sha256=xUhiKlZmQgCnlBvx_072mRMdisi_z9HuINSW7wvzgvY,39756
reactivex/_version.py,sha256=jegJMYuSW90VKiMotVdNAakBvYVPirm-A5oeyJVuhH8,22
reactivex/abc/__init__.py,sha256=qvD2QcDdd3vL89eEhzBqcRpDnHGHMAOLWYr4TqtJpdM,594
reactivex/abc/disposable.py,sha256=DIE-c0MwHEmU1IYD_9v8WNisgn47X0VYJGCAIb9anBo,826
reactivex/abc/observable.py,sha256=Q2UQLzOILTgEWmKa_coUB_YFV7U4Cytr9014mJdTXy0,1334
reactivex/abc/observer.py,sha256=m8zfu2MR3Iuc0kIOfEVGzQUBIoKrmZGHRFLPd_Orhic,1150
reactivex/abc/periodicscheduler.py,sha256=dviU37-fPN_rRR9g1OyOxrW5d3zP_AKIfcodoK_NDo8,1344
reactivex/abc/scheduler.py,sha256=DLWlL5uhFClEE3OKIMraodxqP0qT_9spkC6kCLjowsM,4362
reactivex/abc/startable.py,sha256=C_L9Q-ooHslSNthYapLwEJgG-KD5cSkOCnDeTa-rw0o,266
reactivex/abc/subject.py,sha256=1j5jJrvdlYaK4oFeObjpD1M_gKkZBAPiVnqR9WjOL1w,1907
reactivex/disposable/__init__.py,sha256=EqOgh0GrHv578Dwq3APgPjB8eYD4vVE1qQJ056LhCrs,658
reactivex/disposable/booleandisposable.py,sha256=jbH7Qbkcjon7YkvbtWjHOd_h2DJaNg2NFd2tg0cwMh0,482
reactivex/disposable/compositedisposable.py,sha256=nCinmCt--aCyltvZ5v2Kj8c4JddLx04Ihpd9zwmGhkw,2816
reactivex/disposable/disposable.py,sha256=qJHh7EWE6k5zcI_p9BwUooFHAD3VkndgExvAbJSpEC0,1132
reactivex/disposable/multipleassignmentdisposable.py,sha256=Xc-orSPzypavx2bvXFjzbEkF5ov-UPbOhMZpgir8ROY,1419
reactivex/disposable/refcountdisposable.py,sha256=op7U4ZVPGz26qBCW-UWdV4GDoBqgztUxqcMzlurvEXU,2484
reactivex/disposable/scheduleddisposable.py,sha256=BYaETQ9LysWPYc21XFiA0TLRbWMu-eDSXXdznSrAE8Y,1149
reactivex/disposable/serialdisposable.py,sha256=pJsWQyTV2hCDWn8o8bY8MeL0ERYeqGpVV4OaRZHrUj4,1723
reactivex/disposable/singleassignmentdisposable.py,sha256=pzCdcP-eJQGoXm24phls8QPAcLPS_hkcwOdxErv5O7s,1595
reactivex/internal/__init__.py,sha256=P2T5xg1uq3zUHf5GRHZd4m2RxUH2Rpd_HPq0k7WC8L4,730
reactivex/internal/basic.py,sha256=xi-tuNm2dScLEjZBWDqFV9jQ4MwOrRWu91zJI_GD_Rk,673
reactivex/internal/concurrency.py,sha256=4j9LDDVZvaHgki3mSF01NCv8MOI_xEcPwVrDijfvxtM,691
reactivex/internal/constants.py,sha256=mCLIqaIhFDTe83oAoPmRNdBHJFINCjvOKqJlgYMGSiI,132
reactivex/internal/exceptions.py,sha256=eQ6z4Me2hdtRn3NGPGKZtB76TmI1R4nDIpnbxJQBY-s,1003
reactivex/internal/priorityqueue.py,sha256=GC1OWyGHk3sDPCtBkgyJs5T1iadXLX6i8UtPcg6ibP4,1491
reactivex/internal/utils.py,sha256=GtHsPfim2syw-q6_bpvoE40jdvAHL4Ag5A2veTvaNtw,1809
reactivex/notification.py,sha256=O54boOqdr-_Uy4uTjqm9bCKdH1vxsr4Ln9rd4GR8ebA,6298
reactivex/observable/__init__.py,sha256=rx4_4eShoAgulw7fgEHjP6o7kXMPKlPp0Ht9nvD9rOY,213
reactivex/observable/amb.py,sha256=s82aaIXF94z8faaCahpfu7vATnhM2JX1I3QH8Iv4SZw,677
reactivex/observable/case.py,sha256=nfG5i1j5L9oUJYEx3YlqjoA0IERz3jsdkFCWXAW9jIw,893
reactivex/observable/catch.py,sha256=iV2TcivGIjHWb2S4lhlX84xkKOHfX7FFyLh-GJCn0YY,2566
reactivex/observable/combinelatest.py,sha256=BBz05LZiFBov8-SvdpdORhU0VydgYzqPRaET16r8gkU,2223
reactivex/observable/concat.py,sha256=UvMYssA20vhf-tkNAq9SDGIXWNH2D_Q6lxkLjgAVAZ8,1884
reactivex/observable/connectableobservable.py,sha256=fh16uLWJSgDTTUtl_sUTWL9hPc-tWtfN4DK8-43oBq8,2756
reactivex/observable/defer.py,sha256=sfHQm6IlrwwkY3bAkxOWLVvQJGLsLzTUytbN543KvmI,1408
reactivex/observable/empty.py,sha256=jFELiog8feo5HxCLZ1BdetmRxKynypBUYdXoTh5Y5fg,616
reactivex/observable/forkjoin.py,sha256=XEhWxx20gbT2ZL9slMT0QGWA45iniCq_egcZiOe4Sio,2189
reactivex/observable/fromcallback.py,sha256=zZQu9UWOI1CfDzlcyoLae6qeZIFdxkWpu7HiGQw0OxY,1878
reactivex/observable/fromfuture.py,sha256=tI7-HbCiA0hVoZZfpUPW-bRbX7XcHtRA93FmfX5m3wo,1405
reactivex/observable/fromiterable.py,sha256=wgVVoYnSUGHNKBU6ZT7QAtjksQpDUvKcCWCO1NU6Uk0,1652
reactivex/observable/generate.py,sha256=RWYxDukbOAtfFC5xPhjuH1OuDgw5x0frKW7uTRjdXp8,1647
reactivex/observable/generatewithrelativetime.py,sha256=2L9pwfY2sx2T23B6P4ApV042UaS2UXFbc3a3UrGo3jI,2711
reactivex/observable/groupedobservable.py,sha256=aaySQ7vx5bHwXsHZxpaCJjI5Y87baL07_PnZRjP7jQE,1300
reactivex/observable/ifthen.py,sha256=fOoKAg9Rw7t6E83uM3aRoK8iEbLEwexab5mSBtpRHJg,1667
reactivex/observable/interval.py,sha256=nE4p-DD1DjThkVYJ9SJWWGbWrNFkUV3DzVffk_A1L8I,271
reactivex/observable/marbles.py,sha256=YLb9gsGWfynMtCO_9tmICUWlBulRTeY1erNvTUeMChM,9254
reactivex/observable/merge.py,sha256=EOZONxkkgq20oB9Q1_lPch0BXwR3KU6FpG8FDnqZ-7M,284
reactivex/observable/never.py,sha256=HmnZPq2b3bcJyKW2iZLeEAhH-gWxAZjcpeqirVpxFaE,605
reactivex/observable/observable.py,sha256=3_BiiaSizmfaGb-nbICQAhf6MlH4hynM_5l63gwZZcM,11482
reactivex/observable/onerrorresumenext.py,sha256=U095TAz5LQ_bi9k_Gsf0nwi6zlkNAeAFz6wpgO-Eh4I,2222
reactivex/observable/range.py,sha256=fCpgUh8_R3UNBeuvy_sQPLvEui_qSASWEbXk-uZZqm4,2151
reactivex/observable/repeat.py,sha256=gts_BxFEobJxr4RvB37g6iX9R4Vei0dYOogq1e7NmZk,890
reactivex/observable/returnvalue.py,sha256=bmyU60ZBPgj_jB3II7CoYXitcahDOs8Nprgm579GfUI,1933
reactivex/observable/start.py,sha256=PNbLPq_D5oV7T5TMIayBRCcYy9oalmBu5ea7noiB-4g,1091
reactivex/observable/startasync.py,sha256=BOu75YH2oa0I23bsz89fVxtc7pZEqzgxIQQX3RpVZ_4,409
reactivex/observable/throw.py,sha256=T8ccsu_ikGFk8incIrKFEng_TXojlPCdY_UiXEYzhn8,754
reactivex/observable/timer.py,sha256=MkxxL3feuzG3kqpVHcoYXvTjfbzlliX3jVcIlPPy9Eg,4498
reactivex/observable/toasync.py,sha256=AzUHl7-CFBTWsjWr15eIwNReZMMyXTnfJTDlJIzPwBw,1694
reactivex/observable/using.py,sha256=Y3ZbxO_dS9SGaI6zwjVXFOZmtdtQ1FHadamoE03tTjg,1689
reactivex/observable/withlatestfrom.py,sha256=wIs-YV8AD-dA60mtLLnRnIGUDF7IaVrRSnL3npD8dEU,1987
reactivex/observable/zip.py,sha256=DHR_4WGQ8HTdZwvoKL-ykdTYArEvYA-PvYdzKSPEmKA,2828
reactivex/observer/__init__.py,sha256=kzNSuynaSXVopszVbAHemaMi8QckLukg3HapjFd5qTg,268
reactivex/observer/autodetachobserver.py,sha256=AtokqzYC9YoWmf4krJw3KoZU3o-l9QOG3BZokaSeuVs,1710
reactivex/observer/observeonobserver.py,sha256=4VXsFvS9XLySlllx92G6XRbzXoymbDuge7wfGJUdrmM,494
reactivex/observer/observer.py,sha256=LfG-WtWE9rReIxZcjsDGInbdOG8k6rLy4Jt9FzWExZA,3520
reactivex/observer/scheduledobserver.py,sha256=EsaN8BP9ZaPbCzhMJbVjWxcoGk0-WHX3Z3MJrNrcd8k,2189
reactivex/operators/__init__.py,sha256=25nkSxdpoFYqp25XakOGXYuHaHSRS1r_5drUm42vfnI,132458
reactivex/operators/_all.py,sha256=Q_E4tAY6CNNqRxJAd-bkupKEwhj29CSR9VvFCjj-DTE,497
reactivex/operators/_amb.py,sha256=ivtjF1nHWykfYuwRBVEj1RgsSueUftK6inmQ9zVIxsI,3076
reactivex/operators/_asobservable.py,sha256=7XeRHYCbf0nRywnRBKOa6FeJZoUPpOdYas04IUiKH-8,821
reactivex/operators/_average.py,sha256=E3WHAmQsa45QFbrkNrp2aW-hQJJdNXWe8ivOJ4Wkn1Y,1685
reactivex/operators/_buffer.py,sha256=aoBaRCbQXZgaFSmO1Re6tMm4_TCLP0Lya5UKeEZdqXQ,2206
reactivex/operators/_bufferwithtime.py,sha256=8IljnQa_nmm6_2GUbyKI3MEpHH5KbqTYix5dmiB3hGU,619
reactivex/operators/_bufferwithtimeorcount.py,sha256=GvagRPU_gnM4xJ_HOdZ7XYmMf4FNGv0vCsP-nqWbNNc,557
reactivex/operators/_catch.py,sha256=9ffgARW8H51S7dNB-ZThc28BNVZQXkfjQvVPqZ-sMco,2575
reactivex/operators/_combinelatest.py,sha256=45UDZGrQtm0PX2gmaLexKNWWoVx01fR4MCWWtxnSmYk,798
reactivex/operators/_concat.py,sha256=8ziLOjVcxs96Vc4msyP_11U7lYi7F9X1F6whXSYAHK0,695
reactivex/operators/_contains.py,sha256=j3Iva5NadCLrzp0lu12OlRZZiNoVAxBWG9HTG5kGuy8,581
reactivex/operators/_count.py,sha256=dwsii7oxDq2HRdSq7MOHzMHOgbjiBPHu3ZoLR2FCmuA,558
reactivex/operators/_debounce.py,sha256=sNWOLGZmIunYjKfslzwNQqDqSO7WM1m8b6qATJ2A07w,5562
reactivex/operators/_defaultifempty.py,sha256=Ld-4sxUO-yHHYQRHIMy4aCWasy1rDZJNV05Szjokk6k,1456
reactivex/operators/_delay.py,sha256=uzyQywJAv5tiQ5DKknu6ESecW117eaXGIzUwf370JGI,4722
reactivex/operators/_delaysubscription.py,sha256=xLSAFuGMtHQdWjw8S1h2o46255nkbd0chDuHSZw3sxA,994
reactivex/operators/_delaywithmapper.py,sha256=ZoOjh8-ehIZKjN7lLmQ-7zVTf7US-CBusuYIsZuDnCQ,3511
reactivex/operators/_dematerialize.py,sha256=Ai4yXRnbqs5qor3fy5PyUJkx9i-L09PuK5Uv9c20t1s,1091
reactivex/operators/_distinct.py,sha256=q_Rb9uJz5gAf3QeNe2bg8U71T4My3QrnvTPZArBGcbg,2516
reactivex/operators/_distinctuntilchanged.py,sha256=-SnZF4qheq3FwpFyk5ZZWCB6z6wT37xIwcrHZe6t5kc,2869
reactivex/operators/_do.py,sha256=NaRy0fcHdzVPRLqLE1VSPLbZyYwWip3cPiiJTXnrVJI,10795
reactivex/operators/_dowhile.py,sha256=uXEnZLz_tfSW8rUXVnki5UlP0tvRbZ3TPEC7q3QJ61s,817
reactivex/operators/_elementatordefault.py,sha256=J1Nb2WpOs2iIxOnP84TdVuHPl4n9ySM_lVmAfdqR69E,1546
reactivex/operators/_exclusive.py,sha256=Q5p_Duez_i2xxy0BkTyO_VdxVFBbWSAbhgWodgiY47k,2479
reactivex/operators/_expand.py,sha256=q9aUkvffLhzam_O0-xhgGprvkhfmZNaXbtU2c4SCqTo,3078
reactivex/operators/_filter.py,sha256=x4GU4BH0wRkh_xnA5Js3JaDQ_wZ7Krp0w99TnC-xir8,2807
reactivex/operators/_finallyaction.py,sha256=GCF-sBwTg4aqh7cnyRbN4JIAnHZZQEPjWDXQdGsR9cs,1302
reactivex/operators/_find.py,sha256=GE1xEG06I8ojugiTy6qCq4od15EWSPmGMCTz54Dawy0,1433
reactivex/operators/_first.py,sha256=cvcl5Mx3btw9m48J3J5ubTobOTI0YYLxeFE6tSRKR74,1176
reactivex/operators/_firstordefault.py,sha256=1ZMxi0mr5uuyUAz6XrA5Y3G94O18A1HnIjeFTWxiT-s,2557
reactivex/operators/_flatmap.py,sha256=R9MnotDaMPTie7FK-fZcMkmke2KF42AZl6y5pAa410U,4279
reactivex/operators/_forkjoin.py,sha256=qkQKndnP2DcY60nAp6Cjq_tJuyS9Z3IGwmGebD5Imk4,843
reactivex/operators/_groupby.py,sha256=FLN5ykLpHalUQbk2H5ENm33tgoRYyDS6kBcQ0_-ZCM0,852
reactivex/operators/_groupbyuntil.py,sha256=mO-xW1vBlBPMhw1fjOA7K3RRon9MIsrJy8jbRWw9jzY,6308
reactivex/operators/_groupjoin.py,sha256=9N-WQsfOwFT0oqvcM5KyKj6wH6rY-5wLe6vo-8MDArY,5886
reactivex/operators/_ignoreelements.py,sha256=6szHhX7hjEf5UBRBGQslyUHm03XeT5d41A_cWKKkoUs,929
reactivex/operators/_isempty.py,sha256=jeVsO7KUJ3TrKns3616gGpGP7k8yOvj4pr0LZZQP9jc,534
reactivex/operators/_join.py,sha256=7KZAECRvb339vlZYfAatrFLGGYSjYgN7adZvaSPs41E,4592
reactivex/operators/_last.py,sha256=0DV-uHOH_0I6qR6shWISXi1-sb8Rk_5GrPUN28_-RA8,1138
reactivex/operators/_lastordefault.py,sha256=DsgpzcoFqZ-dV4BafyR_fU5Gu6dJebuQd4Bhw-3aols,1968
reactivex/operators/_map.py,sha256=lmBF2kPEJoNKqaxbUkF4J90s5rgCHWrv8mnDcql-lHk,2129
reactivex/operators/_materialize.py,sha256=Su1xY0GrbjfuXi2WvDBSq3Far1M3ZpoXsmSfXN1GwKg,1455
reactivex/operators/_max.py,sha256=ZgzlqX9zBqllmzVSbxjabRMMqk9s1uT_3IyUhEASY54,995
reactivex/operators/_maxby.py,sha256=-0gH-YJuz-p8cQWXJOqAKn1s50vnvSbi5r32tJ92lHg,1018
reactivex/operators/_merge.py,sha256=04vqPKtnLxpB9vUcHABsR7YWCGW4mycPWVtPp1Hu0r0,5185
reactivex/operators/_min.py,sha256=jEd9YXx9_TATN33g17PSwEErLDpsxhMTb7sfoIQUOCQ,1173
reactivex/operators/_minby.py,sha256=zAV1m2yG59hzJCGdsf_fayk0Inmw1pBm8e6fg-_rZhQ,2501
reactivex/operators/_multicast.py,sha256=Spuwm-rwyaSgL5C-HPijjGmVavttQnHznovVCX6uqfg,2939
reactivex/operators/_observeon.py,sha256=j-mneWR9fXq_XmOqdLvC0rn0FNhf8cbjsh09mFqT_4c,1212
reactivex/operators/_onerrorresumenext.py,sha256=tGol6SbZlrQge2Je0HUfSvdN6rURAXe03K3EoY6Yr5U,419
reactivex/operators/_pairwise.py,sha256=8Nx6OaDjTAxu-nK_nziObjt1-sQskH1EKFsiTBw91zI,1670
reactivex/operators/_partition.py,sha256=O4mANzYnvFZZed6x92GK_oMV10zCkz6lTUD-5U7hjzk,3022
reactivex/operators/_pluck.py,sha256=l6uteIyv2tVPxPDb36STgoumAIH9YmJNAcX3vRFyG0U,1208
reactivex/operators/_publish.py,sha256=PFHQQInn6dYuKeSFn8oJX6NfsRQde5xNva1S0BGdbnU,2240
reactivex/operators/_publishvalue.py,sha256=SVoAvEwF0re7U9oYNFVTb5NewpRTZY4Q-VvBFK5Un14,901
reactivex/operators/_reduce.py,sha256=sKpDIPFr7pw8Gi1cz3HZbidRnc3-hKgb1Zq2FkcOQoQ,1570
reactivex/operators/_repeat.py,sha256=ru1fh1IL-_l5AP2KawhsIK6nrPvnZrjxsX-cARWi8B4,1069
reactivex/operators/_replay.py,sha256=pz4yYMQ4pRuEkZoXv4j0SBmTNNQ8xXBrTsvV2rI_b7E,2430
reactivex/operators/_retry.py,sha256=xNdJe6OAhHgouYlso82bW-Ce-1scAXfa5GddfYVYilQ,1083
reactivex/operators/_sample.py,sha256=t7V1V9I8giJjSgEKPTE-8sxX-4zUJipItEfPz0kAAEw,2123
reactivex/operators/_scan.py,sha256=BpzkQl3FBQMWPWkc5gcc52pWLWnCiYiHErgq13od7ZA,1732
reactivex/operators/_sequenceequal.py,sha256=I11OjMgjMUZOrqmCPYz1_5kDlpVxKnnou2YuhS2nOCQ,4148
reactivex/operators/_single.py,sha256=oCDg0DPsGHWgWhVe4E1GHAOI0CGLRpwK4i3nxzo0iuo,1139
reactivex/operators/_singleordefault.py,sha256=qWKXGNIuMdZkmZag-LNJSbmYtdxLy3sN3diKHFHCooM,2840
reactivex/operators/_skip.py,sha256=rMZBIjjtg2eNDIWgXCMzPnTLXqC9d7vu1cZhgkHopBo,1332
reactivex/operators/_skiplast.py,sha256=95Nq8Onfafjqyd_-0kjH_elFEYm9YDumTBfjsGoCPRs,1590
reactivex/operators/_skiplastwithtime.py,sha256=MqEMeEEwI1wCfCK1eWYsqYntmYpoWWh8gozymfXaq4M,2352
reactivex/operators/_skipuntil.py,sha256=UUYfpCHnXU4Eg7tS-ljRDIH_Zjzf79ckYBkb6ihZw68,2133
reactivex/operators/_skipuntilwithtime.py,sha256=O3lC8eDkjUuQcTUsHJBNEjs6HXXCkkITEbXGuD6XSlc,2252
reactivex/operators/_skipwhile.py,sha256=JDPrpNX9HS62GVyT422pznnXfpkO06xbR3JFll-tWfc,2205
reactivex/operators/_skipwithtime.py,sha256=JtRB0BsPDDF_P32zJ0K1e6iF0H5f6ZgS7Ao2ULNrL9c,2220
reactivex/operators/_slice.py,sha256=w4TutKAOt8IzNGANLv7RqDro5gOIdMaTCcLgVLV0gBs,2311
reactivex/operators/_some.py,sha256=8RSPk3mX4hm8geo49CTu8UGVkQqMHChncr1y2RXIGnA,1656
reactivex/operators/_startswith.py,sha256=wbhJz2cHLwPVnd9lsJAcdcgn0srSZks6pxIHElvE_Hc,689
reactivex/operators/_subscribeon.py,sha256=WPL3l6F79pYH-__8oyy0hoCtI6JCQ6J6QBjFmE-rM5Q,1744
reactivex/operators/_sum.py,sha256=xtgLpIgK7qh5tjh0WpefDns_LzpAGAX9sWRIOd_J3KE,511
reactivex/operators/_switchlatest.py,sha256=FYEPWYipGrQb4sgNVRHdYyM7B3ybc5Hm_6su471TRr8,2908
reactivex/operators/_take.py,sha256=xZZykFL90MOz7Uy7DtYHAc26QiRFNbgRNfpMFx5ijuQ,1437
reactivex/operators/_takelast.py,sha256=WwkJKxdIg73qNF-mxQnUx6aTO1vYxn1p_q_9_11DPfI,1619
reactivex/operators/_takelastbuffer.py,sha256=vGrQdVPblAHzbNVPMvzIlRkMafD5yoN30WJy5L5cwc0,1695
reactivex/operators/_takelastwithtime.py,sha256=foNqsRSSrZYp2ixrenCR-xzED2HaYKNFxtecUGx6pb4,2338
reactivex/operators/_takeuntil.py,sha256=LHq_Lr1l3nk_YBCPyP0vsemhSKRZpXWLumhPdbPpDjI,1515
reactivex/operators/_takeuntilwithtime.py,sha256=094FkE1vH2fBkQAEC-fN9awc4gs1bmMU1Pu12L2raQk,1706
reactivex/operators/_takewhile.py,sha256=ZmPTbx_ROPF9JS_fqcG3oqs2SsOoCiebOccFwNbZ-cM,3612
reactivex/operators/_takewithtime.py,sha256=jajLiqRc4sIPsRIaqjcir5yCB3zSnrogoaMXMgDKF1s,1850
reactivex/operators/_throttlefirst.py,sha256=HAHaIK1FQ8fSOkwsenemsDh4AdlVk8Yrd0bUYBlhWx8,1887
reactivex/operators/_timeinterval.py,sha256=q7FqU8hWO9_-_FwckgoumeLYpCx4upeq_jsF0o_RTZ0,1553
reactivex/operators/_timeout.py,sha256=6FfEwqmfodvqtXvBxEXCmpdTvsYCiQ_AnOOJAwxlqOE,3248
reactivex/operators/_timeoutwithmapper.py,sha256=VjM_DoqylWBY7R6_tY2WtoLymml-yIqgfDCV28Pd23Q,4408
reactivex/operators/_timestamp.py,sha256=P1_NUuEJiCSe9s0whhdfEyFvGdIhNB6aKNxkvkhd9FI,1347
reactivex/operators/_todict.py,sha256=YIXOJLMW4NKXJOxkfXMyQdfT9slM8s8DGtdbXl_QlzY,1972
reactivex/operators/_tofuture.py,sha256=iEcdUPqaGDweTvciRkTEqSR_Xk3zjSrNfC8ukOnn-Hc,2061
reactivex/operators/_toiterable.py,sha256=6dw1ph6-cihnyEsnHULlyMzCx1wYkASx2alKDYZPvwU,1170
reactivex/operators/_tomarbles.py,sha256=kmQmhK2qJtIRcWxIKY09vFXAcms_9XSd9lsXpMFf4ME,2314
reactivex/operators/_toset.py,sha256=2XIcr5xUURaf6qlvy7590znLs2wyJuLTf5rm2alpd9s,996
reactivex/operators/_whiledo.py,sha256=-3t6FTMTIGjZHE2vfdRsWzclzotYsQjI_hYV-eOLZfk,1071
reactivex/operators/_window.py,sha256=dpBG0GK_nW8_fbC19ceCMl6A_Io9EkrCWtIClvrqVvM,5176
reactivex/operators/_windowwithcount.py,sha256=9ueOFkZ3JtJ16Tn1Bsu3kqzgKoD1jV-h3SDCLqLMcyg,2698
reactivex/operators/_windowwithtime.py,sha256=RFuyNs0pWqC7_FgCI9pJUp8PuLC2Q9un-uy-K3G34Rg,3859
reactivex/operators/_windowwithtimeorcount.py,sha256=SUx5Id39IqjGSeAYa_qD5yrb_HOPUJOdNWHbvWKdtEk,3113
reactivex/operators/_withlatestfrom.py,sha256=v7fwpdHcPBxP8Fvmf-4_XVo_K0rfhcC2i2hx8GQNmjE,898
reactivex/operators/_zip.py,sha256=h0ay0I7OtWFyJpT5-8s_FG6YbWK0vJdS7xYMfGQLSu4,2383
reactivex/operators/connectable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
reactivex/operators/connectable/_refcount.py,sha256=f8d3B0lUrROMjX4sm7tvaCsyaBnRQm6S1HNmedXm_jg,1419
reactivex/pipe.py,sha256=yO-T0-cNJwUR5hgPuu8zoOrRaVlplwK5WHw3I7wP5Fw,4207
reactivex/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
reactivex/run.py,sha256=LKeIqZG8yMtu3vLBCtxWKa5RUYCTzZnuKdnQzDNciFM,1709
reactivex/scheduler/__init__.py,sha256=N0qMXVK3FlQJ1h25kVr9dLshBMWayEeWcNcfFen4bnY,856
reactivex/scheduler/catchscheduler.py,sha256=KoYfPlLyhQvNRC3ue9E74tAAJuy0GlZNgu04Q3RMnB0,6130
reactivex/scheduler/currentthreadscheduler.py,sha256=cJv0UjzT92FSe3sWxRzi4b-irV-2_xsVhjjLV4lxoGA,2657
reactivex/scheduler/eventloop/__init__.py,sha256=wyCjpar6vxFyPvv_FM0N56FTinxnTqGs9MMBWY_2Gsc,468
reactivex/scheduler/eventloop/asyncioscheduler.py,sha256=rfG7D34YxbhuMtT4OoZlEjsDE6Sqo78IEG63pvDCD6k,3790
reactivex/scheduler/eventloop/asynciothreadsafescheduler.py,sha256=WPWLsxnzRviwbdDfg5HnXISExXk0ZjouOVEMY4mQ36s,5026
reactivex/scheduler/eventloop/eventletscheduler.py,sha256=5ENX1cEw1KPDXz4YmrWcfkKFs5VK9SI_xiBPa-Kmu1E,3660
reactivex/scheduler/eventloop/geventscheduler.py,sha256=aZDZY3eUWE3rtBBNaVFBz-jpAX7TdqPh3l6p94MaWGo,3700
reactivex/scheduler/eventloop/ioloopscheduler.py,sha256=FSu0ROfJ3RYBp6VeZlji23UjB7P0qlQUQl4hyS4GXsk,3941
reactivex/scheduler/eventloop/twistedscheduler.py,sha256=ZDhU3cGwVzpnFZHtD7VSbGhZmv3AjwBWjQGHNOsoz74,3373
reactivex/scheduler/eventloopscheduler.py,sha256=bWz0mIWu76lqnRV-zoZ9LLPXQJF-otm05vFHbGxJiok,7421
reactivex/scheduler/historicalscheduler.py,sha256=7ytM1qNWBBSnxWMoiOUCtSnot8AfTKEz0f_nBzGjacM,620
reactivex/scheduler/immediatescheduler.py,sha256=0ZZgDRcA3U89X-IP0vED711HHla8lxfuGAFFSuM4q3o,3121
reactivex/scheduler/mainloop/__init__.py,sha256=Lwy7VFLsygEMpVUQ0wkOsdFe-slCHK1gedydyOA2Dwc,325
reactivex/scheduler/mainloop/gtkscheduler.py,sha256=KLLa1B1SHh35HBHe5UZpjjk1D9KlBVAktyohlnnVbjw,4399
reactivex/scheduler/mainloop/pygamescheduler.py,sha256=yAglz1rCFRUtKiI4Dfc32bKyls7-US7ELrTJHylVMDM,3514
reactivex/scheduler/mainloop/qtscheduler.py,sha256=rI7MBuKtnyCAVoyLj9zUc1kWT4zWVd-mfpdUIYFcJ2A,4476
reactivex/scheduler/mainloop/tkinterscheduler.py,sha256=PSmKn06nEo5HW4jNdqKTktZiSDM6z5JFBxcf3qw0vso,2987
reactivex/scheduler/mainloop/wxscheduler.py,sha256=Z1SjND81O3DNgqNg7C-6xRCcvRVIDwFyM_YnmyMGJK8,5522
reactivex/scheduler/newthreadscheduler.py,sha256=K7l0ovBthzpG3uxn3t1MQRHqlbRVyhI0Boko8-d4X-0,4199
reactivex/scheduler/periodicscheduler.py,sha256=m4ghE-odJrhiJASy6U1yviVYu18olBvjDNgnTX2LMpk,1878
reactivex/scheduler/scheduleditem.py,sha256=SnWep-Zk3o2EvgfcaHrJeAJqmSdt3LK3KSpNb8L6k80,1433
reactivex/scheduler/scheduler.py,sha256=L5nIuOC-a3StedJErx4iL3FY9ayh3QntEwlZpA3h4bs,5400
reactivex/scheduler/threadpoolscheduler.py,sha256=yAE_hgTlcvV4GIsgVwc5XxZmg13-1Hf8aWaoz3eKYXo,1254
reactivex/scheduler/timeoutscheduler.py,sha256=IJUzB0yfCDF_aFRYONT4kifZx0wTGA0KMacT_TKlUt0,3516
reactivex/scheduler/trampoline.py,sha256=3sp1sV1NgNJK78enC1jqbReSj7jf_j9GNfibM-SfKcs,1847
reactivex/scheduler/trampolinescheduler.py,sha256=mcU14rsCf03kIDbsF0weWH-BJnGul4WoNUYx4yIh9f0,3788
reactivex/scheduler/virtualtimescheduler.py,sha256=JbT8K7ewVzubQ3odxfpCI2FNRl3cIHfkv_-cZT10OTM,7693
reactivex/subject/__init__.py,sha256=ICiGMqswVSo5wqaZzLF04Tz66pY_zAcyJRff2-XoT7A,229
reactivex/subject/asyncsubject.py,sha256=4y7fIOSQmS7lhaEzg-3O7BOPJjRghV49OItPuhefK9g,2569
reactivex/subject/behaviorsubject.py,sha256=1WY5d6ntgkUCnn3ZZ3ifvP4yoGUDH08ODVJN7dHRUQI,1997
reactivex/subject/innersubscription.py,sha256=sukkq8AQ6WkJfTsLTYh51sUwB3BbR4DsJ9M2Vkyc0qg,703
reactivex/subject/replaysubject.py,sha256=07yT1Aq8G5cSKvlsvE4OljKpMCDb3Myh3tCAqnDnMp4,4610
reactivex/subject/subject.py,sha256=Q8nj-PHurq2QaNH_tbtJIZ5lRDkNUoen0NDDZjpF3bE,3148
reactivex/testing/__init__.py,sha256=hPkeUUVcp0MiwNTn1jii5UZXkJaz51S44GV7U9SA86E,356
reactivex/testing/coldobservable.py,sha256=IfXBEpHqD5XdfBsxg90UlVzIIiarew8NbyB6P9e294U,1943
reactivex/testing/hotobservable.py,sha256=N89Kj7eS92b_xrSa8ACI9BiMrj-0Ze_gA4dv0GEwKFs,2081
reactivex/testing/marbles.py,sha256=DQ9viMf-aqrpUKjLxE6exat9YUjmRBwokWDTK6vVxNI,5765
reactivex/testing/mockdisposable.py,sha256=GZxvMeGSwwDI-N1C856XwGPkPdN0CNZkf7C80GQ3fPQ,436
reactivex/testing/mockobserver.py,sha256=03y2EOIN5xdZYtEDWlvGQ-ZrTLUdFw3MZfjCDsmnKVs,780
reactivex/testing/reactivetest.py,sha256=xgwA9RMu7lhyJVhh6c-QqGX5-CKJ8VWy-sipt-GlBH4,2119
reactivex/testing/recorded.py,sha256=8eL6IOZuBb12rp_UAlWiU2YiiKOUkd92PQzBi5pXG8A,1095
reactivex/testing/subscription.py,sha256=VCVc6kZJmR8c89rkaAECmFth8NOkz4tUs45PjnnUNnk,701
reactivex/testing/testscheduler.py,sha256=CYlbxcFzdfdx2XVXkIVdWTVB9lSC5DoaoxfSRQw63HI,5881
reactivex/typing.py,sha256=IRRs3TNKClakoVm26NHRei0ZtEFbKPC27AaKdp7ZzNI,1367
@@ -1,20 +0,0 @@
# The MIT License
Copyright 2013-2022, Dag Brattli, Microsoft Corp., and Contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
Metadata-Version: 2.1
Name: timezonefinder
Version: 8.1.0
@@ -0,0 +1 @@
timezonefinder
+25
View File
@@ -0,0 +1,25 @@
from timezonefinder.timezonefinder import (
TimezoneFinder,
TimezoneFinderL,
)
# Import module-level functions
from timezonefinder.global_functions import (
timezone_at,
timezone_at_land,
unique_timezone_at,
certain_timezone_at,
get_geometry,
)
# https://docs.python.org/3/tutorial/modules.html#importing-from-a-package
# determines which objects will be imported with "import *"
__all__ = (
"TimezoneFinder",
"TimezoneFinderL",
"timezone_at",
"timezone_at_land",
"unique_timezone_at",
"certain_timezone_at",
"get_geometry",
)
@@ -0,0 +1,52 @@
"""'transparent' numba functionality replacements
njit decorator
data types
dtype_2int_tuple = typeof((1, 1))
@njit(b1(i4, i4, i4[:, :]), cache=True)
@njit(dtype_2int_tuple(f8, f8), cache=True)
"""
# decorator
def njit(*args, **kwargs):
def wrapper(f):
return f
return wrapper
class SubscriptAndCallable:
def __init__(self, *args, **kwargs):
pass
def __class_getitem__(cls, item):
return None
def __call__(self, arg):
# for example int64(1) must work
return arg
# DTYPES
class f8(SubscriptAndCallable):
pass
class i8(SubscriptAndCallable):
pass
class i4(SubscriptAndCallable):
pass
class boolean(SubscriptAndCallable):
pass
class Array(SubscriptAndCallable):
pass
+49
View File
@@ -0,0 +1,49 @@
"""optionally builds inside polygon algorithm C extension
Resources:
https://github.com/FirefoxMetzger/mini-extension
https://stackoverflow.com/questions/60073711/how-to-build-c-extensions-via-poetry
https://github.com/libmbd/libmbd/blob/master/build.py
"""
import pathlib
import re
from typing import Optional
import warnings
import cffi
EXTENSION_NAME = "inside_polygon_ext"
H_FILE_NAME = "inside_polygon_int.h"
C_FILE_NAME = "inside_polygon_int.c"
EXTENSION_PATH = pathlib.Path("timezonefinder") / "inside_poly_extension"
h_file_path = EXTENSION_PATH / H_FILE_NAME
c_file_path = EXTENSION_PATH / C_FILE_NAME
ffibuilder: Optional[cffi.FFI] = None
try:
ffibuilder = cffi.FFI()
except Exception as exc:
# Clang extension should be fully optional
warnings.warn(
f"C lang extension cannot be build, since cffi failed with this error: {exc}"
)
if ffibuilder is not None:
ffibuilder.set_source(
"timezonefinder." + EXTENSION_NAME,
source='#include "inside_polygon_int.h"',
sources=[str(c_file_path)],
include_dirs=[str(EXTENSION_PATH)],
)
with open(h_file_path) as h_file:
# cffi does not like our preprocessor directives, so we remove them
lns = h_file.read().splitlines()
flt = filter(lambda ln: not re.match(r" *#", ln), lns)
ffibuilder.cdef("\n".join(flt))
if __name__ == "__main__":
if ffibuilder:
ffibuilder.compile(verbose=True)
+122
View File
@@ -0,0 +1,122 @@
import argparse
import contextlib
import os
import sys
import tempfile
from typing import Callable, Generator
from timezonefinder import (
TimezoneFinderL,
timezone_at,
certain_timezone_at,
timezone_at_land,
)
@contextlib.contextmanager
def redirect_stdout_to_temp_file() -> Generator[str, None, None]:
"""
Context manager that redirects stdout to a temporary file for the duration of the context.
The temporary file is created but not deleted when the context exits.
Returns the path to the temporary file.
"""
# Save the original stdout
original_stdout = sys.stdout
# Create a temporary file that will NOT be automatically deleted
temp_fd, temp_path = tempfile.mkstemp(text=True)
temp_file = os.fdopen(temp_fd, "w")
try:
# Redirect stdout to the temporary file
sys.stdout = temp_file
yield temp_path
finally:
# Restore the original stdout and close the file
sys.stdout = original_stdout
temp_file.close()
def get_timezone_function(function_id: int) -> Callable:
"""
Get the appropriate timezone function based on the function ID.
Uses global functions when available, otherwise creates instances as needed.
"""
# Use global functions for TimezoneFinder methods
if function_id == 0:
return timezone_at
elif function_id == 1:
return certain_timezone_at
elif function_id == 5:
return timezone_at_land
# For TimezoneFinderL methods, still create an instance
tf_instance = TimezoneFinderL()
functions = {
3: tf_instance.timezone_at,
4: tf_instance.timezone_at_land,
}
return functions[function_id]
def main() -> None:
parser = argparse.ArgumentParser(description="parse TimezoneFinder parameters")
parser.add_argument("lng", type=float, help="longitude to be queried")
parser.add_argument("lat", type=float, help="latitude to be queried")
parser.add_argument("-v", action="store_true", help="verbosity flag")
parser.add_argument(
"-f",
"--function",
type=int,
choices=[0, 1, 3, 4, 5],
default=0,
help="function to be called:"
"0: TimezoneFinder.timezone_at(), "
"1: TimezoneFinder.certain_timezone_at(), "
"2: removed, "
"3: TimezoneFinderL.timezone_at(), "
"4: TimezoneFinderL.timezone_at_land(), "
"5: TimezoneFinder.timezone_at_land(), ",
)
parsed_args = parser.parse_args() # takes input from sys.argv
timezone_function = get_timezone_function(parsed_args.function)
verbose_mode = parsed_args.v
# Always redirect stdout to a temp file
with redirect_stdout_to_temp_file() as temp_file_path:
print("\n" + "=" * 60)
print("TIMEZONEFINDER LOOKUP DETAILS")
print("-" * 60)
print(f"Coordinates: {parsed_args.lat:.6f}°, {parsed_args.lng:.6f}° (lat, lng)")
print(
f"Function {timezone_function.__name__} (function ID: {parsed_args.function})"
)
# Execute the timezone function
tz = timezone_function(lng=parsed_args.lng, lat=parsed_args.lat)
if tz:
print(f"Result: Found timezone '{tz}'")
else:
print("Result: No timezone found at this location")
print("=" * 60)
if verbose_mode:
# In verbose mode, print the contents of the temp file
try:
with open(temp_file_path) as f:
captured_output = f.read().strip()
if captured_output:
print(captured_output)
except Exception as e:
print(f"Warning: Could not read captured output: {e}")
else:
# In non-verbose mode, just print the result
print(tz if tz else "")
# Always clean up the temp file
try:
os.remove(temp_file_path)
except Exception:
pass
+89
View File
@@ -0,0 +1,89 @@
import os
from pathlib import Path
from typing import Any, Dict, List, Tuple, Union
import numpy as np
# SHORTCUT SETTINGS
# h3 library
SHORTCUT_H3_RES: int = 3
OCEAN_TIMEZONE_PREFIX = r"Etc/GMT"
# PATHS
PACKAGE_DIR = Path(__file__).parent
DEFAULT_DATA_DIR = PACKAGE_DIR / "data"
# i = signed 4byte integer
NR_BYTES_I = 4
# IMPORTANT: all values between -180 and 180 degree must fit into the domain of i4!
# is the same as testing if 360 fits into the domain of I4 (unsigned!)
MAX_ALLOWED_COORD_VAL = 2 ** (8 * NR_BYTES_I - 1)
# from math import floor,log10
# DECIMAL_PLACES_SHIFT = floor(log10(MAX_ALLOWED_COORD_VAL/180.0)) # == 7
DECIMAL_PLACES_SHIFT = 7
INT2COORD_FACTOR = 10 ** (-DECIMAL_PLACES_SHIFT)
COORD2INT_FACTOR = 10**DECIMAL_PLACES_SHIFT
MAX_LNG_VAL = 180.0
MAX_LAT_VAL = 90.0
MAX_LNG_VAL_INT = int(MAX_LNG_VAL * COORD2INT_FACTOR)
MAX_LAT_VAL_INT = int(MAX_LAT_VAL * COORD2INT_FACTOR)
MAX_INT_VAL = MAX_LNG_VAL_INT
assert MAX_INT_VAL < MAX_ALLOWED_COORD_VAL
# TYPES
# used in Numba JIT compiled function signatures in utils_numba.py
# NOTE: Changes in the global settings might not immediately affect
# the functions due to caching!
# Type alias for flexibility with integer types (pure int or numpy integer scalars)
IntegerLike = Union[int, np.integer]
# hexagon id to list of polygon ids
ShortcutMapping = Dict[int, np.ndarray]
CoordPairs = List[Tuple[float, float]]
CoordLists = List[List[float]]
IntLists = List[List[int]]
# zone id storage settings ---------------------------------------------------
_ZONE_ID_DTYPE_ALIASES: Dict[str, "np.dtype[Any]"] = {
"uint8": np.dtype("<u1"),
"uint16": np.dtype("<u2"),
}
def _normalise_zone_id_dtype_key(key: str) -> str:
"""Normalise user provided dtype keys to canonical form."""
return key.lower().strip()
def get_zone_id_dtype(name: str) -> "np.dtype[Any]":
"""Return the configured numpy dtype for storing zone IDs."""
try:
return _ZONE_ID_DTYPE_ALIASES[_normalise_zone_id_dtype_key(name)]
except KeyError as exc: # pragma: no cover - defensive, validated on import
valid = ", ".join(sorted(_ZONE_ID_DTYPE_ALIASES))
raise ValueError(
f"Unsupported zone id dtype '{name}'. Choose one of: {valid}"
) from exc
def zone_id_dtype_to_string(dtype: np.dtype) -> str:
"""Return the little-endian numpy dtype string for serialisation."""
return dtype.newbyteorder("<").str
def available_zone_id_dtype_names() -> Tuple[str, ...]:
"""Return the supported zone id dtype names."""
return tuple(sorted(_ZONE_ID_DTYPE_ALIASES))
DEFAULT_ZONE_ID_DTYPE_NAME = os.getenv("TIMEZONEFINDER_ZONE_ID_DTYPE", "uint8")
DEFAULT_ZONE_ID_DTYPE = get_zone_id_dtype(DEFAULT_ZONE_ID_DTYPE_NAME)
+173
View File
@@ -0,0 +1,173 @@
"""
Coordinate accessors for timezonefinder.
This module provides classes for accessing polygon coordinates
either directly from file or from preloaded memory.
"""
from abc import ABC, abstractmethod
import mmap
from pathlib import Path
from typing import Dict
import numpy as np
from timezonefinder import utils
from timezonefinder.flatbuf.generated.polygons.PolygonCollection import (
PolygonCollection,
)
from timezonefinder.flatbuf.io.polygons import (
get_polygon_collection,
read_polygon_array_from_binary,
)
class AbstractCoordAccessor(ABC):
"""Abstract base class defining the interface for coordinate accessors."""
@abstractmethod
def __init__(self, coordinate_file_path: Path):
"""
Initialize the coordinate accessor.
Args:
coordinate_file_path: Path to the coordinate file
"""
pass
@abstractmethod
def __getitem__(self, idx: int) -> np.ndarray:
"""
Get the polygon coordinates for the given index.
Args:
idx: The polygon index
Returns:
A numpy array containing the polygon coordinates
"""
pass
def __del__(self):
"""
Ensure resources are cleaned up when the object is destroyed.
"""
self.cleanup()
@abstractmethod
def cleanup(self) -> None:
"""Clean up resources."""
pass
class FileCoordAccessor(AbstractCoordAccessor):
"""Accessor that reads polygon coordinates from the file on demand."""
def __init__(self, coordinate_file_path: Path):
"""
Initialize the file-based coordinate accessor.
Args:
coordinate_file_path: Path to the coordinate file
"""
self.coordinate_file_path = coordinate_file_path
# Initialize file resources using proper resource management.
try:
# Use memory-mapped file for on-demand reading
self.coord_file: object = open(self.coordinate_file_path, "rb")
# Create memory map
self.coord_buf: mmap.mmap = mmap.mmap(
self.coord_file.fileno(), 0, access=mmap.ACCESS_READ
)
self.polygon_collection: PolygonCollection = get_polygon_collection(
self.coord_buf
)
except Exception:
# Clean up any partially initialized resources
self.cleanup()
raise
def __getitem__(self, idx: int) -> np.ndarray:
"""
Get the polygon coordinates for the given index.
Args:
idx: The polygon index
Returns:
A numpy array containing the polygon coordinates
"""
return read_polygon_array_from_binary(self.polygon_collection, idx)
def cleanup(self) -> None:
"""Clean up resources."""
utils.close_resource(self.coord_file)
utils.close_resource(self.coord_buf)
del self.polygon_collection
class MemoryCoordAccessor(AbstractCoordAccessor):
"""Accessor that preloads all polygon coordinates into memory."""
def __init__(self, coordinate_file_path: Path):
"""
Initialize the memory-based coordinate accessor.
Args:
coordinate_file_path: Path to the coordinate file
"""
# Read entire file into memory
with open(coordinate_file_path, "rb") as f:
coord_buf = f.read()
# Initialize polygon collection
polygon_collection = get_polygon_collection(coord_buf)
# Get number of polygons
num_polygons = polygon_collection.PolygonsLength()
# Preload all polygons
self.polygons: Dict[int, np.ndarray] = {}
for idx in range(num_polygons):
self.polygons[idx] = read_polygon_array_from_binary(polygon_collection, idx)
# Once polygons are loaded, we don't need to keep polygon_collection or coord_buf references
# They'll be garbage collected
def __getitem__(self, idx: int) -> np.ndarray:
"""
Get the polygon coordinates for the given index.
Args:
idx: The polygon index
Returns:
A numpy array containing the polygon coordinates
"""
return self.polygons[idx]
def cleanup(self) -> None:
"""Clean up resources."""
del self.polygons
# Just clear the dictionary, no file resources to clean up
if hasattr(self, "polygons"):
self.polygons.clear()
def create_coord_accessor(
coordinate_file_path: Path, in_memory: bool
) -> AbstractCoordAccessor:
"""
Factory function to create the appropriate coordinate accessor.
Args:
coordinate_file_path: Path to the coordinate file
in_memory: Whether to use in-memory mode
Returns:
An instance of a coordinate accessor
"""
if in_memory:
return MemoryCoordAccessor(coordinate_file_path)
else:
return FileCoordAccessor(coordinate_file_path)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,302 @@
{
"10": [
1,
0
],
"151": [
2,
21
],
"153": [
1,
23
],
"155": [
2,
24
],
"167": [
1,
26
],
"177": [
1,
27
],
"19": [
3,
1
],
"208": [
1,
28
],
"218": [
21,
29
],
"231": [
1,
50
],
"268": [
2,
51
],
"316": [
8,
53
],
"389": [
3,
61
],
"391": [
2,
64
],
"40": [
8,
4
],
"41": [
6,
12
],
"410": [
5,
66
],
"414": [
2,
71
],
"481": [
1,
73
],
"488": [
2,
74
],
"515": [
1,
76
],
"518": [
1,
77
],
"522": [
16,
78
],
"685": [
2,
94
],
"721": [
15,
96
],
"725": [
44,
111
],
"728": [
2,
155
],
"729": [
37,
157
],
"730": [
20,
194
],
"733": [
1,
214
],
"736": [
28,
215
],
"737": [
3,
243
],
"741": [
1,
246
],
"742": [
17,
247
],
"743": [
4,
264
],
"748": [
2,
268
],
"750": [
1,
270
],
"753": [
2,
271
],
"754": [
5,
273
],
"755": [
3,
278
],
"756": [
14,
281
],
"761": [
12,
295
],
"762": [
3,
307
],
"765": [
1,
310
],
"769": [
1,
311
],
"771": [
7,
312
],
"776": [
21,
319
],
"781": [
3,
340
],
"790": [
1,
343
],
"793": [
5,
344
],
"800": [
2,
349
],
"804": [
1,
351
],
"806": [
2,
352
],
"809": [
2,
354
],
"810": [
4,
356
],
"812": [
13,
360
],
"814": [
17,
373
],
"817": [
2,
390
],
"819": [
1,
392
],
"820": [
11,
393
],
"824": [
2,
404
],
"828": [
13,
406
],
"829": [
1,
419
],
"830": [
4,
420
],
"833": [
6,
424
],
"834": [
13,
430
],
"838": [
6,
443
],
"841": [
4,
449
],
"844": [
32,
453
],
"848": [
34,
485
],
"851": [
37,
519
],
"854": [
22,
556
],
"855": [
1,
578
],
"91": [
1,
18
],
"98": [
2,
19
]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,92 @@
Etc/UTC
Africa/Abidjan
Europe/Moscow
Africa/Lagos
Africa/Johannesburg
Africa/Cairo
Africa/Casablanca
Europe/Paris
America/Adak
America/Anchorage
America/Caracas
America/Sao_Paulo
America/Lima
America/Mexico_City
America/Denver
America/Chicago
America/Phoenix
America/New_York
America/Halifax
America/Havana
America/Los_Angeles
America/Miquelon
America/Noronha
America/Nuuk
America/Santiago
America/St_Johns
Asia/Manila
Asia/Jakarta
Australia/Brisbane
Australia/Sydney
Asia/Karachi
Pacific/Auckland
Antarctica/Troll
Pacific/Fiji
Asia/Dubai
Asia/Beirut
Asia/Dhaka
Asia/Tokyo
Asia/Kolkata
Europe/Athens
Asia/Gaza
Asia/Jerusalem
Asia/Kabul
Asia/Kathmandu
Asia/Sakhalin
Asia/Tehran
Asia/Yangon
Atlantic/Azores
Europe/Lisbon
Atlantic/Cape_Verde
Australia/Adelaide
Australia/Darwin
Australia/Eucla
Australia/Lord_Howe
Europe/Chisinau
Europe/Dublin
Europe/London
Pacific/Tongatapu
Pacific/Chatham
Pacific/Easter
Pacific/Gambier
Pacific/Honolulu
Pacific/Kiritimati
Pacific/Marquesas
Pacific/Pago_Pago
Pacific/Norfolk
Pacific/Pitcairn
Etc/GMT-12
Etc/GMT-11
Etc/GMT-10
Etc/GMT-9
Etc/GMT-8
Etc/GMT-7
Etc/GMT-6
Etc/GMT-5
Etc/GMT-4
Etc/GMT-3
Etc/GMT-2
Etc/GMT-1
Etc/GMT
Etc/GMT+1
Etc/GMT+2
Etc/GMT+3
Etc/GMT+4
Etc/GMT+5
Etc/GMT+6
Etc/GMT+7
Etc/GMT+8
Etc/GMT+9
Etc/GMT+10
Etc/GMT+11
Etc/GMT+12
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,5 @@
"""FlatBuffer schemas, bindings, and IO helpers used by timezonefinder."""
from . import generated, io, schemas
__all__ = ["generated", "io", "schemas"]
@@ -0,0 +1,7 @@
"""Auto-generated FlatBuffer bindings grouped by domain."""
__all__ = [
"polygons",
"shortcuts_uint8",
"shortcuts_uint16",
]
@@ -0,0 +1,92 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: polygons
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class Polygon:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = Polygon()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsPolygon(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# Polygon
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# Polygon
def Coords(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(
flatbuffers.number_types.Int32Flags,
a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4),
)
return 0
# Polygon
def CoordsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int32Flags, o)
return 0
# Polygon
def CoordsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# Polygon
def CoordsIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def PolygonStart(builder):
builder.StartObject(1)
def Start(builder):
PolygonStart(builder)
def PolygonAddCoords(builder, coords):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(coords), 0
)
def AddCoords(builder, coords):
PolygonAddCoords(builder, coords)
def PolygonStartCoordsVector(builder, numElems):
return builder.StartVector(4, numElems, 4)
def StartCoordsVector(builder, numElems):
return PolygonStartCoordsVector(builder, numElems)
def PolygonEnd(builder):
return builder.EndObject()
def End(builder):
return PolygonEnd(builder)
@@ -0,0 +1,88 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: polygons
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class PolygonCollection:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = PolygonCollection()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsPolygonCollection(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# PolygonCollection
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# PolygonCollection
def Polygons(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
x = self._tab.Vector(o)
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
x = self._tab.Indirect(x)
from timezonefinder.flatbuf.generated.polygons.Polygon import Polygon
obj = Polygon()
obj.Init(self._tab.Bytes, x)
return obj
return None
# PolygonCollection
def PolygonsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# PolygonCollection
def PolygonsIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def PolygonCollectionStart(builder):
builder.StartObject(1)
def Start(builder):
PolygonCollectionStart(builder)
def PolygonCollectionAddPolygons(builder, polygons):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(polygons), 0
)
def AddPolygons(builder, polygons):
PolygonCollectionAddPolygons(builder, polygons)
def PolygonCollectionStartPolygonsVector(builder, numElems):
return builder.StartVector(4, numElems, 4)
def StartPolygonsVector(builder, numElems):
return PolygonCollectionStartPolygonsVector(builder, numElems)
def PolygonCollectionEnd(builder):
return builder.EndObject()
def End(builder):
return PolygonCollectionEnd(builder)
@@ -0,0 +1,90 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint16
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class HybridShortcutCollection:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = HybridShortcutCollection()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsHybridShortcutCollection(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# HybridShortcutCollection
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# HybridShortcutCollection
def Entries(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
x = self._tab.Vector(o)
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
x = self._tab.Indirect(x)
from timezonefinder.flatbuf.generated.shortcuts_uint16.HybridShortcutEntry import (
HybridShortcutEntry,
)
obj = HybridShortcutEntry()
obj.Init(self._tab.Bytes, x)
return obj
return None
# HybridShortcutCollection
def EntriesLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# HybridShortcutCollection
def EntriesIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def HybridShortcutCollectionStart(builder):
builder.StartObject(1)
def Start(builder):
HybridShortcutCollectionStart(builder)
def HybridShortcutCollectionAddEntries(builder, entries):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(entries), 0
)
def AddEntries(builder, entries):
HybridShortcutCollectionAddEntries(builder, entries)
def HybridShortcutCollectionStartEntriesVector(builder, numElems):
return builder.StartVector(4, numElems, 4)
def StartEntriesVector(builder, numElems):
return HybridShortcutCollectionStartEntriesVector(builder, numElems)
def HybridShortcutCollectionEnd(builder):
return builder.EndObject()
def End(builder):
return HybridShortcutCollectionEnd(builder)
@@ -0,0 +1,97 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint16
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class HybridShortcutEntry:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = HybridShortcutEntry()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsHybridShortcutEntry(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# HybridShortcutEntry
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# HybridShortcutEntry
def HexId(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(
flatbuffers.number_types.Uint64Flags, o + self._tab.Pos
)
return 0
# HybridShortcutEntry
def ValueType(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0
# HybridShortcutEntry
def Value(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
from flatbuffers.table import Table
obj = Table(bytearray(), 0)
self._tab.Union(obj, o)
return obj
return None
def HybridShortcutEntryStart(builder):
builder.StartObject(3)
def Start(builder):
HybridShortcutEntryStart(builder)
def HybridShortcutEntryAddHexId(builder, hexId):
builder.PrependUint64Slot(0, hexId, 0)
def AddHexId(builder, hexId):
HybridShortcutEntryAddHexId(builder, hexId)
def HybridShortcutEntryAddValueType(builder, valueType):
builder.PrependUint8Slot(1, valueType, 0)
def AddValueType(builder, valueType):
HybridShortcutEntryAddValueType(builder, valueType)
def HybridShortcutEntryAddValue(builder, value):
builder.PrependUOffsetTRelativeSlot(
2, flatbuffers.number_types.UOffsetTFlags.py_type(value), 0
)
def AddValue(builder, value):
HybridShortcutEntryAddValue(builder, value)
def HybridShortcutEntryEnd(builder):
return builder.EndObject()
def End(builder):
return HybridShortcutEntryEnd(builder)
@@ -0,0 +1,92 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint16
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class PolygonList:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = PolygonList()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsPolygonList(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# PolygonList
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# PolygonList
def PolyIds(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(
flatbuffers.number_types.Uint16Flags,
a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 2),
)
return 0
# PolygonList
def PolyIdsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint16Flags, o)
return 0
# PolygonList
def PolyIdsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# PolygonList
def PolyIdsIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def PolygonListStart(builder):
builder.StartObject(1)
def Start(builder):
PolygonListStart(builder)
def PolygonListAddPolyIds(builder, polyIds):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(polyIds), 0
)
def AddPolyIds(builder, polyIds):
PolygonListAddPolyIds(builder, polyIds)
def PolygonListStartPolyIdsVector(builder, numElems):
return builder.StartVector(2, numElems, 2)
def StartPolyIdsVector(builder, numElems):
return PolygonListStartPolyIdsVector(builder, numElems)
def PolygonListEnd(builder):
return builder.EndObject()
def End(builder):
return PolygonListEnd(builder)
@@ -0,0 +1,9 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint16
class ShortcutValue:
NONE = 0
UniqueZone = 1
PolygonList = 2
@@ -0,0 +1,61 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint16
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class UniqueZone:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = UniqueZone()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsUniqueZone(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# UniqueZone
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# UniqueZone
def ZoneId(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(
flatbuffers.number_types.Uint16Flags, o + self._tab.Pos
)
return 0
def UniqueZoneStart(builder):
builder.StartObject(1)
def Start(builder):
UniqueZoneStart(builder)
def UniqueZoneAddZoneId(builder, zoneId):
builder.PrependUint16Slot(0, zoneId, 0)
def AddZoneId(builder, zoneId):
UniqueZoneAddZoneId(builder, zoneId)
def UniqueZoneEnd(builder):
return builder.EndObject()
def End(builder):
return UniqueZoneEnd(builder)
@@ -0,0 +1,90 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint8
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class HybridShortcutCollection:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = HybridShortcutCollection()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsHybridShortcutCollection(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# HybridShortcutCollection
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# HybridShortcutCollection
def Entries(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
x = self._tab.Vector(o)
x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
x = self._tab.Indirect(x)
from timezonefinder.flatbuf.generated.shortcuts_uint8.HybridShortcutEntry import (
HybridShortcutEntry,
)
obj = HybridShortcutEntry()
obj.Init(self._tab.Bytes, x)
return obj
return None
# HybridShortcutCollection
def EntriesLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# HybridShortcutCollection
def EntriesIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def HybridShortcutCollectionStart(builder):
builder.StartObject(1)
def Start(builder):
HybridShortcutCollectionStart(builder)
def HybridShortcutCollectionAddEntries(builder, entries):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(entries), 0
)
def AddEntries(builder, entries):
HybridShortcutCollectionAddEntries(builder, entries)
def HybridShortcutCollectionStartEntriesVector(builder, numElems):
return builder.StartVector(4, numElems, 4)
def StartEntriesVector(builder, numElems):
return HybridShortcutCollectionStartEntriesVector(builder, numElems)
def HybridShortcutCollectionEnd(builder):
return builder.EndObject()
def End(builder):
return HybridShortcutCollectionEnd(builder)
@@ -0,0 +1,97 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint8
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class HybridShortcutEntry:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = HybridShortcutEntry()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsHybridShortcutEntry(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# HybridShortcutEntry
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# HybridShortcutEntry
def HexId(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.Get(
flatbuffers.number_types.Uint64Flags, o + self._tab.Pos
)
return 0
# HybridShortcutEntry
def ValueType(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
return 0
# HybridShortcutEntry
def Value(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
if o != 0:
from flatbuffers.table import Table
obj = Table(bytearray(), 0)
self._tab.Union(obj, o)
return obj
return None
def HybridShortcutEntryStart(builder):
builder.StartObject(3)
def Start(builder):
HybridShortcutEntryStart(builder)
def HybridShortcutEntryAddHexId(builder, hexId):
builder.PrependUint64Slot(0, hexId, 0)
def AddHexId(builder, hexId):
HybridShortcutEntryAddHexId(builder, hexId)
def HybridShortcutEntryAddValueType(builder, valueType):
builder.PrependUint8Slot(1, valueType, 0)
def AddValueType(builder, valueType):
HybridShortcutEntryAddValueType(builder, valueType)
def HybridShortcutEntryAddValue(builder, value):
builder.PrependUOffsetTRelativeSlot(
2, flatbuffers.number_types.UOffsetTFlags.py_type(value), 0
)
def AddValue(builder, value):
HybridShortcutEntryAddValue(builder, value)
def HybridShortcutEntryEnd(builder):
return builder.EndObject()
def End(builder):
return HybridShortcutEntryEnd(builder)
@@ -0,0 +1,92 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: shortcuts_uint8
import flatbuffers
from flatbuffers.compat import import_numpy
np = import_numpy()
class PolygonList:
__slots__ = ["_tab"]
@classmethod
def GetRootAs(cls, buf, offset=0):
n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
x = PolygonList()
x.Init(buf, n + offset)
return x
@classmethod
def GetRootAsPolygonList(cls, buf, offset=0):
"""This method is deprecated. Please switch to GetRootAs."""
return cls.GetRootAs(buf, offset)
# PolygonList
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# PolygonList
def PolyIds(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
a = self._tab.Vector(o)
return self._tab.Get(
flatbuffers.number_types.Uint16Flags,
a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 2),
)
return 0
# PolygonList
def PolyIdsAsNumpy(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint16Flags, o)
return 0
# PolygonList
def PolyIdsLength(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
return self._tab.VectorLen(o)
return 0
# PolygonList
def PolyIdsIsNone(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
return o == 0
def PolygonListStart(builder):
builder.StartObject(1)
def Start(builder):
PolygonListStart(builder)
def PolygonListAddPolyIds(builder, polyIds):
builder.PrependUOffsetTRelativeSlot(
0, flatbuffers.number_types.UOffsetTFlags.py_type(polyIds), 0
)
def AddPolyIds(builder, polyIds):
PolygonListAddPolyIds(builder, polyIds)
def PolygonListStartPolyIdsVector(builder, numElems):
return builder.StartVector(2, numElems, 2)
def StartPolyIdsVector(builder, numElems):
return PolygonListStartPolyIdsVector(builder, numElems)
def PolygonListEnd(builder):
return builder.EndObject()
def End(builder):
return PolygonListEnd(builder)

Some files were not shown because too many files have changed in this diff Show More