diff --git a/.github/workflows/smoke-tests.yml b/.github/workflows/smoke-tests.yml index e12244c9c0..641fe87303 100644 --- a/.github/workflows/smoke-tests.yml +++ b/.github/workflows/smoke-tests.yml @@ -360,6 +360,12 @@ jobs: "3.13", "3.14" ] + type: [ + regular + ] + include: + - type: doctest + py-version: '3.12' fail-fast: false steps: @@ -388,6 +394,7 @@ jobs: run: pip install *.whl - name: Install test dependencies + if: ${{ matrix.type != 'doctest' }} run: pip install -r test/requirements.txt - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 @@ -400,6 +407,7 @@ jobs: run: docker run -d --name aerospike -p 3000-3002:3000-3002 -e DEFAULT_TTL=2592000 ${{ env.REGISTRY_NAME }}/aerospike/aerospike-server:${{ env.SERVER_TAG }} - name: Create config.conf + if: ${{ matrix.type != 'doctest' }} run: cp config.conf.template config.conf working-directory: test @@ -408,9 +416,22 @@ jobs: container-name: aerospike - name: Run tests + if: ${{ matrix.type != 'doctest' }} run: python -m pytest ./new_tests -vv -W error::pytest.PytestUnraisableExceptionWarning working-directory: test + - name: Install test dependencies + if: ${{ matrix.type == 'doctest' }} + run: pip install -r doc/requirements.txt + + - if: ${{ matrix.type == 'doctest' }} + name: Run doctest + run: sphinx-build -b doctest . doctest + working-directory: doc + + - if: ${{ !cancelled() }} + run: docker logs aerospike + test-ee: runs-on: ubuntu-22.04 needs: build diff --git a/aerospike_helpers/__init__.py b/aerospike_helpers/__init__.py index bad706b072..133e2e0229 100644 --- a/aerospike_helpers/__init__.py +++ b/aerospike_helpers/__init__.py @@ -20,8 +20,23 @@ class HyperLogLog(bytes): The constructor takes in any argument that the :class:`bytes` constructor takes in. - >>> h = HyperLogLog([1, 2, 3]) - >>> client.put(key, {"hyperloglog": h}) + .. testcode:: + + from aerospike_helpers import HyperLogLog + import aerospike + + h = HyperLogLog([1, 2, 3]) + + client = aerospike.client({'hosts': [('localhost', 3000)]}) + key = ("test", "demo", 1) + client.put(key, {"hyperloglog": h}) + + _, _, bins = client.get(key) + print(bins["hyperloglog"]) + + .. testoutput:: + + HyperLogLog(...) """ def __new__(cls, o) -> "HyperLogLog": return super().__new__(cls, o) diff --git a/aerospike_helpers/batch/records.py b/aerospike_helpers/batch/records.py index 5b0a8cfd92..5bd9fd3696 100644 --- a/aerospike_helpers/batch/records.py +++ b/aerospike_helpers/batch/records.py @@ -81,11 +81,13 @@ def __init__( self, key: tuple, ops: "TypeOps", meta: Optional[dict] = None, policy: "TypeBatchPolicyWrite" = None ) -> None: """ - Example:: + Example: + + .. testcode:: # Create a batch Write to increment bin "a" by 10 and read the result from the record. import aerospike - import aerospike_helpers.operations as op + from aerospike_helpers.operations import operations as op from aerospike_helpers.batch.records import Write bin_name = "a" @@ -140,11 +142,13 @@ def __init__( policy: "TypeBatchPolicyRead" = None, ) -> None: """ - Example:: + Example: + + .. testcode:: # Create a batch Read to read bin "a" from the record. import aerospike - import aerospike_helpers.operations as op + from aerospike_helpers.operations import operations as op from aerospike_helpers.batch.records import Read bin_name = "a" @@ -192,12 +196,15 @@ def __init__( self, key: tuple, module: str, function: str, args: "TypeUDFArgs", policy: "TypeBatchPolicyApply" = None ) -> None: """ - Example:: + Example: + + .. testcode:: # Create a batch Apply to apply UDF "test_func" to bin "a" from the record. # Assume that "test_func" takes a bin name string as an argument. # Assume the appropriate UDF module has already been registered. import aerospike_helpers.operations as op + from aerospike_helpers.batch.records import Apply module = "my_lua" @@ -240,7 +247,9 @@ class Remove(BatchRecord): def __init__(self, key: tuple, policy: "TypeBatchPolicyRemove" = None) -> None: """ - Example:: + Example: + + .. testcode:: # Create a batch Remove to remove the record. import aerospike_helpers.operations as op @@ -251,7 +260,7 @@ def __init__(self, key: tuple, policy: "TypeBatchPolicyRemove" = None) -> None: user_key = 1 key = (namespace, set, user_key) - br = Remove(key, ops) + br = Remove(key) """ super().__init__(key) self._type = _Types.REMOVE @@ -278,7 +287,9 @@ class BatchRecords: def __init__(self, batch_records: Optional[TypeBatchRecordList] = None) -> None: """ - Example:: + Example: + + .. testcode:: import aerospike import aerospike_helpers.operations.operations as op @@ -328,12 +339,15 @@ def __init__(self, batch_records: Optional[TypeBatchRecordList] = None) -> None: for br in brs.batch_records: print(br.result) print(br.record) - # 0 - # (('test', 'demo', 1, bytearray(b'...')), {'ttl': 4294967295, 'gen': 0}, {}) - # 0 - # (('test', 'demo', 2, bytearray(b'...')), {'ttl': 2592000, 'gen': 4}, {'id': 100}) - # 0 - # (('test', 'demo', 3, bytearray(b'...')), {'ttl': 2592000, 'gen': 3}, {'id': 1}) + + .. testoutput:: + + 0 + (('test', 'demo', 1, bytearray(b'...')), {...}, {}) + 0 + (('test', 'demo', 2, bytearray(b'...')), {...}, {'id': 100}) + 0 + (('test', 'demo', 3, bytearray(b'...')), {...}, {'id': 1}) """ if batch_records is None: diff --git a/aerospike_helpers/cdt_ctx.py b/aerospike_helpers/cdt_ctx.py index 7aa758fd40..d886c5fd29 100644 --- a/aerospike_helpers/cdt_ctx.py +++ b/aerospike_helpers/cdt_ctx.py @@ -17,7 +17,9 @@ Helper functions to generate complex data type context (cdt_ctx) objects for use with operations on nested CDTs (list, map, etc). -Example:: +Example: + +.. testcode:: import aerospike from aerospike import exception as ex @@ -51,7 +53,6 @@ _, _, result = client.operate(key, ops) print(result) - # {'users': 200} # Example 2: add a new person and get their rating of Facebook cindy = { @@ -76,11 +77,11 @@ _, _, result = client.operate(key, ops) print(result) - # {'users': 4} # Example 3: create a CDT secondary index from a base64 encoded _cdt_ctx with info command policy = {} + ctx_list_index = [cdt_ctx.cdt_ctx_list_index(0)] bs_b4_cdt = client.get_cdtctx_base64(ctx_list_index) r = [] @@ -101,6 +102,11 @@ client.remove(key) client.close() +.. testoutput:: + + {'users': 200} + {'users': 4} + .. _path_expressions_contexts: Path Expressions Contexts diff --git a/aerospike_helpers/expressions/arithmetic.py b/aerospike_helpers/expressions/arithmetic.py index 8ec1012e17..d231e1a47b 100644 --- a/aerospike_helpers/expressions/arithmetic.py +++ b/aerospike_helpers/expressions/arithmetic.py @@ -53,7 +53,10 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value). - Example:: + Example: + + .. testcode:: + # Integer bin "a" + "b" == 11 expr = exp.Eq(exp.Add(exp.IntBin("a"), exp.IntBin("b")), 11).compile() @@ -86,7 +89,9 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value) - Example:: + Example: + + .. testcode:: # Integer bin "a" - "b" == 11 expr = exp.Eq(exp.Sub(exp.IntBin("a"), exp.IntBin("b")), 11).compile() @@ -117,7 +122,9 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value) - Example:: + Example: + + .. testcode:: # Integer bin "a" * "b" >= 11 expr = exp.GE(exp.Mul(exp.IntBin("a"), exp.IntBin("b")), 11).compile() @@ -150,7 +157,9 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value) - Example:: + Example: + + .. testcode:: # Integer bin "a" / "b" / "c" >= 11 expr = exp.GE(exp.Div(exp.IntBin("a"), exp.IntBin("b"), exp.IntBin("c")), 11).compile() @@ -184,7 +193,9 @@ def __init__(self, base: "TypeFloat", exponent: "TypeFloat"): :return: (float value) - Example:: + Example: + + .. testcode:: # Float bin "a" ** 2.0 == 16.0 expr = exp.Eq(exp.Pow(exp.FloatBin("a"), 2.0), 16.0).compile() @@ -212,7 +223,9 @@ def __init__(self, num: "TypeFloat", base: "TypeFloat"): :return: (float value) - Example:: + Example: + + .. testcode:: # For float bin "a", log("a", 2.0) == 16.0 expr = exp.Eq(exp.Log(exp.FloatBin("a"), 2.0), 16.0).compile() @@ -240,7 +253,9 @@ def __init__(self, numerator: "TypeInteger", denominator: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # For int bin "a" % 10 == 0 expr = exp.Eq(exp.Mod(exp.IntBin("a"), 10), 0).compile() @@ -270,7 +285,9 @@ def __init__(self, value: "TypeNumber"): :return: (number value) - Example:: + Example: + + .. testcode:: # For int bin "a", abs("a") == 1 expr = exp.Eq(exp.Abs(exp.IntBin("a")), 1).compile() @@ -300,7 +317,9 @@ def __init__(self, value: "TypeFloat"): :return: (float value) - Example:: + Example: + + .. testcode:: # Floor(2.25) == 2.0 expr = exp.Eq(exp.Floor(2.25), 2.0).compile() @@ -331,7 +350,9 @@ def __init__(self, value: "TypeFloat"): :return: (float value) - Example:: + Example: + + .. testcode:: # Ceil(2.25) == 3.0 expr = exp.Eq(exp.Ceil(2.25), 3.0).compile() @@ -357,7 +378,9 @@ def __init__(self, value: "TypeFloat"): :return: (integer value) - Example:: + Example: + + .. testcode:: #For float bin "a", int(exp.FloatBin("a")) == 2 expr = exp.Eq(exp.ToInt(exp.FloatBin("a")), 2).compile() @@ -379,7 +402,9 @@ def __init__(self, value: "TypeInteger"): :return: (float value) - Example:: + Example: + + .. testcode:: #For int bin "a", float(exp.IntBin("a")) == 2 expr = exp.Eq(exp.ToFloat(exp.IntBin("a")), 2).compile() @@ -404,7 +429,9 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value). - Example:: + Example: + + .. testcode:: # for integer bins a, b, c, min(a, b, c) > 0 expr = exp.GT(exp.Min(exp.IntBin("a"), exp.IntBin("b"), exp.IntBin("c")), 0).compile() @@ -428,7 +455,9 @@ def __init__(self, *args: "TypeNumber"): :return: (integer or float value). - Example:: + Example: + + .. testcode:: # for integer bins a, b, c, max(a, b, c) > 100 expr = exp.GT(exp.Max(exp.IntBin("a"), exp.IntBin("b"), exp.IntBin("c")), 100).compile() diff --git a/aerospike_helpers/expressions/base.py b/aerospike_helpers/expressions/base.py index e4280fb642..e263e48faa 100644 --- a/aerospike_helpers/expressions/base.py +++ b/aerospike_helpers/expressions/base.py @@ -85,7 +85,9 @@ class Unknown(_BaseExpr): def __init__(self): """:return: (unknown value) - Example:: + Example: + + .. testcode:: from aerospike_helpers.expressions.arithmetic import Add @@ -122,7 +124,9 @@ class KeyInt(_Key): def __init__(self): """:return: (integer value): Integer value of the key if the key is an integer. - Example:: + Example: + + .. testcode:: # Integer record key >= 10000. expr = exp.GE(exp.KeyInt(), 10000).compile() @@ -140,7 +144,9 @@ class KeyStr(_Key): def __init__(self): """:return: (string value): string value of the key if the key is an string. - Example:: + Example: + + .. testcode:: # string record key == "aaa". expr = exp.Eq(exp.KeyStr(), "aaa").compile() @@ -158,7 +164,9 @@ class KeyBlob(_Key): def __init__(self): """:return: (blob value): Blob value of the key if the key is a blob. - Example:: + Example: + + .. testcode:: # blob record key <= bytearray([0x65, 0x65]). expr = exp.GE(exp.KeyBlob(), bytearray([0x65, 0x65])).compile() @@ -178,7 +186,9 @@ class KeyExists(_BaseExpr): def __init__(self): """:return: (boolean value): True if the record has a stored key, false otherwise. - Example:: + Example: + + .. testcode:: # Key exists in record meta data. expr = exp.KeyExists().compile() @@ -205,7 +215,9 @@ def __init__(self, bin: str): :return: (boolean bin) - Example:: + Example: + + .. testcode:: # Boolean bin "a" is True. expr = exp.BoolBin("a").compile() @@ -227,7 +239,9 @@ def __init__(self, bin: str): :return: (integer bin) - Example:: + Example: + + .. testcode:: # Integer bin "a" == 200. expr = exp.Eq(exp.IntBin("a"), 200).compile() @@ -249,7 +263,9 @@ def __init__(self, bin: str): :return: (string bin) - Example:: + Example: + + .. testcode:: # String bin "a" == "xyz". expr = exp.Eq(exp.StrBin("a"), "xyz").compile() @@ -271,7 +287,9 @@ def __init__(self, bin: str): :return: (float bin) - Example:: + Example: + + .. testcode:: # Float bin "a" > 2.71. expr = exp.GT(exp.FloatBin("a"), 2.71).compile() @@ -293,7 +311,9 @@ def __init__(self, bin: str): :return: (blob bin) - Example:: + Example: + + .. testcode:: #. Blob bin "a" == bytearray([0x65, 0x65]) expr = exp.Eq(exp.BlobBin("a"), bytearray([0x65, 0x65])).compile() @@ -315,10 +335,12 @@ def __init__(self, bin: str): :return: (GeoJSON bin) - Example:: + Example: + + .. testcode:: #GeoJSON bin "a" contained by GeoJSON bin "b". - expr = exp.CmpGeo(GeoBin("a"), exp.GeoBin("b")).compile() + expr = exp.CmpGeo(exp.GeoBin("a"), exp.GeoBin("b")).compile() """ self._fixed = {_Keys.BIN_KEY: bin} @@ -337,7 +359,9 @@ def __init__(self, bin: str): :return: (list bin) - Example:: + Example: + + .. testcode:: from aerospike_helpers.expressions import list as list_exprs @@ -367,7 +391,9 @@ def __init__(self, bin: str): :return: (map bin) - Example:: + Example: + + .. testcode:: from aerospike_helpers.expressions import map as map_exprs @@ -391,7 +417,9 @@ def __init__(self, bin: str): :return: (HyperLogLog bin) - Example:: + Example: + + .. testcode:: # Does HLL bin "a" have a hll_count > 1000000. from aerospike_helpers.expressions import hll @@ -413,7 +441,9 @@ def __init__(self, bin: str): :return: (boolean value): True if bin exists, False otherwise. - Example:: + Example: + + .. testcode:: #Bin "a" exists in record. expr = exp.BinExists("a").compile() @@ -435,7 +465,9 @@ def __init__(self, bin: str): :return: (integer value): returns the bin type. - Example:: + Example: + + .. testcode:: # bin "a" == type string. expr = exp.Eq(exp.BinType("a"), aerospike.AS_BYTES_STRING).compile() @@ -460,7 +492,9 @@ class SetName(_BaseExpr): def __init__(self): """:return: (string value): Name of the set this record belongs to. - Example:: + Example: + + .. testcode:: # Record set name == "myset". expr = exp.Eq(exp.SetName(), "myset").compile() @@ -486,7 +520,9 @@ class DeviceSize(_BaseExpr): def __init__(self): """:return: (integer value): Uncompressed storage size of the record. - Example:: + Example: + + .. testcode:: # Record device size >= 100 KB. expr = exp.GE(exp.DeviceSize(), 100 * 1024).compile() @@ -543,7 +579,9 @@ class LastUpdateTime(_BaseExpr): def __init__(self): """:return: (integer value): When the record was last updated. - Example:: + Example: + + .. testcode:: # Record last update time >= 2020-01-15. expr = exp.GE(exp.LastUpdateTime(), 1577836800).compile() @@ -562,7 +600,9 @@ class SinceUpdateTime(_BaseExpr): def __init__(self): """:return: (integer value): Number of milliseconds since last updated. - Example:: + Example: + + .. testcode:: # Record last updated more than 2 hours ago. expr = exp.GT(exp.SinceUpdateTime(), 2 * 60 * 60 * 1000).compile() @@ -581,7 +621,9 @@ class VoidTime(_BaseExpr): def __init__(self): """:return: (integer value): Expiration time in nanoseconds since 1970-01-01. - Example:: + Example: + + .. testcode:: # Record expires on 2021-01-01. expr = exp.And( @@ -603,7 +645,9 @@ def __init__(self): """:return: (integer value): Number of seconds till the record will expire, returns -1 if the record never expires. - Example:: + Example: + + .. testcode:: # Record expires in less than 1 hour. expr = exp.LT(exp.TTL(), 60 * 60).compile() @@ -623,7 +667,9 @@ class IsTombstone(_BaseExpr): def __init__(self): """:return: (boolean value): True if the record is a tombstone, false otherwise. - Example:: + Example: + + .. testcode:: # Detect deleted records that are in tombstone state. expr = exp.IsTombstone().compile() @@ -643,7 +689,9 @@ def __init__(self, mod: int): :return: (integer value): Value in range 0 and mod (exclusive). - Example:: + Example: + + .. testcode:: # Records that have digest(key) % 3 == 1. expr = exp.Eq(exp.DigestMod(3), 1).compile() @@ -668,7 +716,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" == 11 expr = exp.Eq(exp.IntBin("a"), 11).compile() @@ -688,7 +738,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" not == 13. expr = exp.NE(exp.IntBin("a"), 13).compile() @@ -708,7 +760,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" > 8. expr = exp.GT(exp.IntBin("a"), 8).compile() @@ -728,7 +782,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" >= 88. expr = exp.GE(exp.IntBin("a"), 88).compile() @@ -748,7 +804,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" < 1000. expr = exp.LT(exp.IntBin("a"), 1000).compile() @@ -768,7 +826,9 @@ def __init__(self, expr0: "TypeComparisonArg", expr1: "TypeComparisonArg"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Integer bin "a" <= 1. expr = exp.LE(exp.IntBin("a"), 1).compile() @@ -789,7 +849,9 @@ def __init__(self, options: int, regex_str: str, cmp_str: Union[_BaseExpr, str]) :return: (boolean value) - Example:: + Example: + + .. testcode:: # Select string bin "a" that starts with "prefix" and ends with "suffix". # Ignore case and do not match newline. @@ -813,7 +875,9 @@ def __init__(self, expr0: "TypeGeo", expr1: "TypeGeo"): :return: (boolean value) - Example:: + Example: + + .. testcode:: # Geo bin "point" is within geo bin "region". expr = exp.CmpGeo(exp.GeoBin("point"), exp.GeoBin("region")).compile() @@ -837,7 +901,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (boolean value) - Example:: + Example: + + .. testcode:: # not (a == 0 or a == 10) expr = exp.Not(exp.Or( @@ -858,7 +924,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (boolean value) - Example:: + Example: + + .. testcode:: # (a > 5 || a == 0) && b < 3 expr = exp.And( @@ -881,7 +949,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (boolean value) - Example:: + Example: + + .. testcode:: # (a == 0 || b == 0) expr = exp.Or( @@ -902,7 +972,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (boolean value) - Example:: + Example: + + .. testcode:: # exclusive(a == 0, b == 0) expr = exp.Exclusive( @@ -942,7 +1014,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (boolean value) - Example:: + Example: + + .. testcode:: from aerospike_helpers.expressions.arithmetic import Add, Sub, Mul @@ -981,14 +1055,18 @@ def __init__(self, *exprs: _BaseExpr): ] record = client.operate(keyTuple, ops) print(record) - # (('test', 'demo', 'key', bytearray(b'...')), {'ttl': 2592000, 'gen': 1}, {'results': 70}) client.put(keyTuple, {"operation": "divide"}) record = client.operate(keyTuple, ops) print(record) # Divide isn't supported, so we get -1 - # (('test', 'demo', 'key', bytearray(b'...')), {'ttl': 2592000, 'gen': 2}, {'results': -1}) + + .. testoutput:: + + (('test', 'demo', 'key', bytearray(b'...')), {'ttl': 2592000, 'gen': 1}, {'results': 70}) + (('test', 'demo', 'key', bytearray(b'...')), {'ttl': 2592000, 'gen': 2}, {'results': -1}) + """ self._children = exprs + (_GenericExpr(_ExprOp._AS_EXP_CODE_END_OF_VA_ARGS, 0, {}),) @@ -1010,7 +1088,9 @@ def __init__(self, *exprs: _BaseExpr): :return: (result of scoped expression) - Example:: + Example: + + .. testcode:: # for int bin "a", 5 < a < 10 expr = exp.Let(exp.Def("x", exp.IntBin("a")), @@ -1036,7 +1116,9 @@ def __init__(self, var_name: str, expr: _BaseExpr): :return: (a variable name expression pair) - Example:: + Example: + + .. testcode:: # for int bin "a", 5 < a < 10 expr = exp.Let(exp.Def("x", exp.IntBin("a")), @@ -1062,7 +1144,9 @@ def __init__(self, var_name: str): :return: (value stored in variable) - Example:: + Example: + + .. testcode:: # for int bin "a", 5 < a < 10 expr = exp.Let(exp.Def("x", exp.IntBin("a")), diff --git a/aerospike_helpers/expressions/bitwise.py b/aerospike_helpers/expressions/bitwise.py index ea9f29450d..9e23103f2d 100644 --- a/aerospike_helpers/expressions/bitwise.py +++ b/aerospike_helpers/expressions/bitwise.py @@ -19,7 +19,9 @@ :mod:`Bitwise Operations API ` for binary data. -Example:: +Example: + +.. testcode:: import aerospike_helpers.expressions as exp # Let blob bin "c" == bytearray([3] * 5). @@ -60,7 +62,9 @@ def __init__(self, policy: "TypePolicy", byte_size: int, flags: int, bin: "TypeB :return: Blob value expression of resized blob bin. - Example:: + Example: + + .. testcode:: # Blob bin "c" == bytearray([1] * 5). # Resize blob bin "c" from the front so that the returned value is bytearray([0] * 5 + [1] * 5). @@ -96,7 +100,9 @@ def __init__(self, policy: "TypePolicy", byte_offset: int, value: "TypeBitValue" :return: Resulting blob containing the inserted bytes. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # Insert 3 so that returned value is bytearray([1, 3, 1, 1, 1, 1]). @@ -130,7 +136,9 @@ def __init__(self, policy: "TypePolicy", byte_offset: int, byte_size: int, bin: :return: Resulting blob containing the remaining bytes. - Example:: + Example: + + .. testcode:: # b = bytearray([1, 2, 3, 4, 5]) expr = exp.BitRemove(None, 1, 1, exp.BlobBin("b")).compile() @@ -169,7 +177,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, value: :return: Resulting blob expression with the bits overwritten. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([0] * 5). # Set bit at offset 7 with size 1 bits to 1 to make the returned value bytearray([1, 0, 0, 0, 0]). @@ -205,7 +215,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, value: :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # bitwise Or `8` with the first byte of blob bin c so that the returned value is bytearray([9, 1, 1, 1, 1]). @@ -248,7 +260,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, value: :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # bitwise Xor `1` with the first byte of blob bin c so that the returned value is bytearray([0, 1, 1, 1, 1]) @@ -284,7 +298,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, value: :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # bitwise and `0` with the first byte of blob bin c so that the returned value is bytearray([0, 1, 1, 1, 1]) @@ -327,7 +343,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, bin: "T :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([255] * 5). # bitwise, not, all of "c" to get bytearray([254] * 5). @@ -362,7 +380,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, shift: :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # Bit left shift the first byte of bin "c" to get bytearray([8, 1, 1, 1, 1]). @@ -398,7 +418,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, shift: :return: Resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([8] * 5). # Bit left shift the first byte of bin "c" to get bytearray([4, 8, 8, 8, 8]). @@ -446,7 +468,9 @@ def __init__( :return: resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Assume we have a blob bin of five bytes: bytearray([1, 1, 1, 1, 1]) expr = exp.BitAdd(None, 8, 8, 1, aerospike.BIT_OVERFLOW_FAIL, exp.BlobBin("b")).compile() @@ -498,11 +522,13 @@ def __init__( :return: resulting blob with the bits operated on. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1] * 5). # Bit subtract the second byte of bin "c" to get bytearray([1, 0, 1, 1, 1]) - expr = exp.BitSubtract(None, 8, 8, 1, aerospike.BIT_OVERFLOW_FAIL).compile() + expr = exp.BitSubtract(None, 8, 8, 1, aerospike.BIT_OVERFLOW_FAIL, "c").compile() """ self._children = ( bit_offset, @@ -539,7 +565,9 @@ def __init__(self, policy: "TypePolicy", bit_offset: int, bit_size: int, value: :return: Resulting blob expression with the bits overwritten. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([0] * 5). # Set bit at offset 7 with size 1 bytes to 1 to make the returned value bytearray([1, 0, 0, 0, 0]). @@ -578,7 +606,9 @@ def __init__(self, bit_offset: int, bit_size: int, bin: "TypeBinName"): :return: Blob, bit_size bits rounded up to the nearest byte size. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1, 2, 3, 4, 5). # Get 2 from bin "c". @@ -600,7 +630,9 @@ def __init__(self, bit_offset: int, bit_size: int, bin: "TypeBinName"): :return: Blob, bit_size bits rounded up to the nearest byte size. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([3] * 5). # Count set bits starting at 3rd byte in bin "c" to get count of 6. @@ -627,7 +659,9 @@ def __init__(self, bit_offset: int, bit_size: int, value: bool, bin: "TypeBinNam :return: Index of the left most bit starting from bit_offset set to value. Returns -1 if not found. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([3] * 5). # Scan the first byte of bin "c" for the first bit set to 1. (should get 6) @@ -650,7 +684,9 @@ def __init__(self, bit_offset: int, bit_size: int, value: bool, bin: "TypeBinNam :return: Index of the right most bit starting from bit_offset set to value. Returns -1 if not found. - Example:: + Example: + + .. testcode:: # b = bytearray([1, 0, 0, 0, 128]) expr = exp.BitRightScan(32, 8, True, exp.BlobBin("b")).compile() @@ -677,7 +713,9 @@ def __init__(self, bit_offset: int, bit_size: int, sign: bool, bin: "TypeBinName :return: Integer expression. - Example:: + Example: + + .. testcode:: # Let blob bin "c" == bytearray([1, 2, 3, 4, 5). # Get 2 as an integer from bin "c". diff --git a/aerospike_helpers/expressions/bitwise_operators.py b/aerospike_helpers/expressions/bitwise_operators.py index 73165defc1..65089ab4ff 100644 --- a/aerospike_helpers/expressions/bitwise_operators.py +++ b/aerospike_helpers/expressions/bitwise_operators.py @@ -48,7 +48,9 @@ def __init__(self, *exprs: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", a & 0xff == 0x11 expr = exp.Eq(exp.IntAnd(exp.IntBin("a"), 0xff), 0x11).compile() @@ -71,10 +73,12 @@ def __init__(self, *exprs: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", a | 0x10 not == 0 - expr = exp.NE(exp.IntOr(IntBin("a"), 0x10), 0).compile() + expr = exp.NE(exp.IntOr(exp.IntBin("a"), 0x10), 0).compile() """ self._children = exprs + (_GenericExpr(_ExprOp._AS_EXP_CODE_END_OF_VA_ARGS, 0, {}),) @@ -94,7 +98,9 @@ def __init__(self, *exprs: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", "b", a ^ b == 16 expr = exp.Eq(exp.IntXOr(exp.IntBin("a"), exp.IntBin("b")), 16).compile() @@ -116,7 +122,9 @@ def __init__(self, expr: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", ~ a == 7 expr = exp.Eq(exp.IntNot(exp.IntBin("a")), 7).compile() @@ -139,7 +147,9 @@ def __init__(self, value: "TypeInteger", shift: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", a << 8 > 0xff expr = exp.GT(exp.IntLeftShift(exp.IntBin("a"), 8), 0xff).compile() @@ -162,7 +172,9 @@ def __init__(self, value: "TypeInteger", shift: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", a >>> 8 > 0xff expr = exp.GT(exp.IntRightShift(exp.IntBin("a"), 8), 0xff).compile() @@ -185,7 +197,9 @@ def __init__(self, value: "TypeInteger", shift: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", a >> 8 > 0xff expr = exp.GT(exp.IntArithmeticRightShift(exp.IntBin("a"), 8), 0xff).compile() @@ -207,7 +221,9 @@ def __init__(self, value: "TypeInteger"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", count(a) == 4 expr = exp.Eq(exp.IntCount(exp.IntBin("a")), 4).compile() @@ -234,7 +250,9 @@ def __init__(self, value: "TypeInteger", search: "TypeBool"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", lscan(a, True) == 4 expr = exp.GT(exp.IntLeftScan(exp.IntBin("a"), True), 4).compile() @@ -262,7 +280,9 @@ def __init__(self, value: "TypeInteger", search: "TypeBool"): :return: (integer value) - Example:: + Example: + + .. testcode:: # for int bin "a", rscan(a, True) == 4 expr = exp.GT(exp.IntRightScan(exp.IntBin("a"), True), 4).compile() diff --git a/aerospike_helpers/expressions/hll.py b/aerospike_helpers/expressions/hll.py index 3905e5f075..a2c7ab9552 100644 --- a/aerospike_helpers/expressions/hll.py +++ b/aerospike_helpers/expressions/hll.py @@ -42,6 +42,18 @@ class HLLInit(_BaseExpr): If 1 of index_bit_count or mh_bit_count are set, an existing HLL bin will set that config and retain its current value for the unset config. If the HLL bin does not exist, index_bit_count is required to create it, mh_bit_count is optional. + + .. testsetup:: + + import aerospike + client = aerospike.client({'hosts': [('localhost', 3000)]}) + ops = [ + expr = exp.HLLInit(None, 12, 24, exp.HLLBin("d")) + ] + key = ("test", "demo", 1) + client.operate(key, ops) + + values = [] """ _op = aerospike.OP_HLL_INIT @@ -61,7 +73,9 @@ def __init__( :return: Returns the resulting hll. - Example:: + Example: + + .. testcode:: # Create an HLL with 12 index bits and 24 min hash bits. expr = exp.HLLInit(None, 12, 24, exp.HLLBin("my_hll")) @@ -96,7 +110,9 @@ def __init__( :return: Returns the resulting hll bin after adding elements from list. - Example:: + Example: + + .. testcode:: # Let HLL bin "d" have the following elements, ['key1', 'key2', 'key3'], index_bits 8, mh_bits 8. # Add ['key4', 'key5', 'key6'] so that the returned value is ['key1', 'key2', 'key3', 'key4', 'key5', @@ -128,7 +144,9 @@ def __init__(self, bin: "TypeBinName"): :return: Integer bin, the estimated number of unique elements in an HLL. - Example:: + Example: + + .. testcode:: # Get count from HLL bin "d". expr = exp.HLLGetCount(exp.HLLBin("d")).compile() @@ -148,7 +166,9 @@ def __init__(self, values: "TypeValue", bin: "TypeBinName"): :return: HLL bin representing the set union. - Example:: + Example: + + .. testcode:: # Let HLLBin "d" contain keys ['key%s' % str(i) for i in range(10000)]. # Let values be a list containing HLL objects retrieved from the aerospike database. @@ -173,7 +193,9 @@ def __init__(self, values: "TypeValue", bin: "TypeBinName"): :return: Integer bin, estimated number of elements in the set union. - Example:: + Example: + + .. testcode:: # Let HLLBin "d" contain keys ['key%s' % str(i) for i in range(10000)]. # Let values be a list containing one HLL object with keys ['key%s' % str(i) for i in range(5000, 15000)]. @@ -198,7 +220,9 @@ def __init__(self, values: "TypeValue", bin: "TypeBinName"): :return: Integer bin, estimated number of elements in the set intersection. - Example:: + Example: + + .. testcode:: # Let HLLBin "d" contain keys ['key%s' % str(i) for i in range(10000)]. # Let values be a list containing one HLL object with keys ['key%s' % str(i) for i in range(5000, 15000)]. @@ -223,7 +247,9 @@ def __init__(self, values: "TypeValue", bin: "TypeBinName"): :return: Float bin, estimated similarity between 0.0 and 1.0. - Example:: + Example: + + .. testcode:: # Let HLLBin "d" contain keys ['key%s' % str(i) for i in range(10000)]. # Let values be a list containing one HLL object with keys ['key%s' % str(i) for i in range(5000, 15000)]. @@ -248,7 +274,9 @@ def __init__(self, bin: "TypeBinName"): :return: List bin, a list containing the index_bit_count and minhash_bit_count. - Example:: + Example: + + .. testcode:: # Get description of HLL bin "d". expr = exp.HLLDescribe(exp.HLLBin("d")).compile() @@ -274,7 +302,9 @@ def __init__( :return: 1 if bin may contain any key in list, 0 otherwise. - Example:: + Example: + + .. testcode:: # Check if HLL bin "d" may contain any of the keys in `list`. expr = exp.HLLMayContain(["key1", "key2", "key3"], exp.HLLBin("d")).compile() diff --git a/aerospike_helpers/expressions/list.py b/aerospike_helpers/expressions/list.py index 5efbb4df38..4566716ec8 100644 --- a/aerospike_helpers/expressions/list.py +++ b/aerospike_helpers/expressions/list.py @@ -59,7 +59,9 @@ def __init__(self, ctx: "TypeCTX", policy: "TypePolicy", value: "TypeValue", bin :return: List expression. - Example:: + Example: + + .. testcode:: # Check if length of list bin "a" is > 5 after appending 1 item. listAppendedBy3 = exp.ListAppend(None, None, 3, exp.ListBin("a")) @@ -97,7 +99,9 @@ def __init__(self, ctx: "TypeCTX", policy: "TypePolicy", value: "TypeValue", bin :return: List expression. - Example:: + Example: + + .. testcode:: # Check if length of list bin "a" is > 5 after appending multiple items. listAppendedByTwoItems = exp.ListAppendItems(None, None, [3, 2], exp.ListBin("a")) @@ -140,7 +144,9 @@ def __init__( :return: List expression. - Example:: + Example: + + .. testcode:: # Check if list bin "a" has length > 5 after insert. listInsertedBy3At0 = exp.ListInsert(None, None, 0, 3, exp.ListBin("a")) @@ -182,7 +188,9 @@ def __init__( :return: List expression. - Example:: + Example: + + .. testcode:: # Check if list bin "a" has length > 5 after inserting items. listInsertedByTwoItems = exp.ListInsertItems(None, None, 0, [4, 7], exp.ListBin("a")) @@ -224,11 +232,13 @@ def __init__( :return: List expression. - Example:: + Example: + + .. testcode:: # Check if incremented value in list bin "a" is the largest in the list. # Rank of -1 == largest element - largestListValue = exp.ListGetByRank(None, aerospike.LIST_RETURN_VALUE, exp.ResultType.INTEGER, -1) + largestListValue = exp.ListGetByRank(None, aerospike.LIST_RETURN_VALUE, exp.ResultType.INTEGER, -1, "a") listIncrementedAtIndex1 = exp.ListIncrement(None, None, 1, 5, exp.ListBin("a")) listItemAtIndex1 = exp.ListGetByIndex(None, aerospike.LIST_RETURN_VALUE, exp.ResultType.INTEGER, 1, listIncrementedAtIndex1) @@ -273,7 +283,9 @@ def __init__( :return: List expression. - Example:: + Example: + + .. testcode:: # Get smallest element in list bin "a" after setting index 1 to 10. listSetAtIndex1 = exp.ListSet(None, None, 1, 10, exp.ListBin("a")) @@ -311,7 +323,9 @@ def __init__(self, ctx: "TypeCTX", bin: "TypeBinName"): :return: List expression. - Example:: + Example: + + .. testcode:: # Clear list value of list nested in list bin "a" index 1. from aerospike_helpers import cdt_ctx @@ -341,7 +355,9 @@ def __init__(self, ctx: "TypeCTX", order: int, bin: "TypeBinName"): :return: list expression. - Example:: + Example: + + .. testcode:: # Get value of sorted list bin "a". expr = exp.ListSort(None, aerospike.LIST_SORT_DEFAULT, "a").compile() @@ -369,7 +385,9 @@ def __init__(self, ctx: "TypeCTX", value: "TypeValue", bin: "TypeBinName", inver :return: list expression. - Example:: + Example: + + .. testcode:: # See if list bin "a", with `3` removed, is equal to list bin "b". listRemoved3 = exp.ListRemoveByValue(None, 3, exp.ListBin("a")) @@ -400,7 +418,9 @@ def __init__(self, ctx: "TypeCTX", values: "TypeListValue", bin: "TypeBinName", :return: list expression. - Example:: + Example: + + .. testcode:: # Remove elements with values [1, 2, 3] from list bin "a". expr = exp.ListRemoveByValueList(None, [1, 2, 3], exp.ListBin("a")).compile() @@ -441,7 +461,9 @@ def __init__( :return: list expression. - Example:: + Example: + + .. testcode:: # Remove list of items with values >= 3 and < 7 from list bin "a". expr = exp.ListRemoveByValueRange(None, 3, 7, exp.ListBin("a")).compile() @@ -482,7 +504,9 @@ def __init__( :return: list expression. - Example:: + Example: + + .. testcode:: # Remove elements larger than 4 by relative rank in list bin "a". # Assume list in bin a is: [6, 12, 4, 21] @@ -527,7 +551,9 @@ def __init__( :return: list expression. - Example:: + Example: + + .. testcode:: # Remove 2 elements greater than 4 # Assume list in bin a is: [6, 12, 4, 21] @@ -558,7 +584,9 @@ def __init__(self, ctx: "TypeCTX", index: "TypeIndex", bin: "TypeBinName"): :return: list expression. - Example:: + Example: + + .. testcode:: # Get size of list bin "a" after index 3 has been removed. expr = exp.ListSize(None, exp.ListRemoveByIndex(None, 3, exp.ListBin("a"))).compile() @@ -586,7 +614,9 @@ def __init__(self, ctx: "TypeCTX", index: "TypeIndex", bin: "TypeBinName", inver :return: list expression. - Example:: + Example: + + .. testcode:: # Remove all elements starting from index 3 in list bin "a". expr = exp.ListRemoveByIndexRangeToEnd(None, 3, exp.ListBin("a")).compile() @@ -624,7 +654,9 @@ def __init__( :return: list expression. - Example:: + Example: + + .. testcode:: # Get size of list bin "a" after index 3, 4, and 5 have been removed. expr = exp.ListSize(None, exp.ListRemoveByIndexRange(None, 3, 3, exp.ListBin("a"))).compile() @@ -653,7 +685,9 @@ def __init__(self, ctx: "TypeCTX", rank: "TypeRank", bin: "TypeBinName"): :return: list expression. - Example:: + Example: + + .. testcode:: # Remove smallest value in list bin "a". expr = exp.ListRemoveByRank(None, 0, exp.ListBin("a")).compile() @@ -681,7 +715,9 @@ def __init__(self, ctx: "TypeCTX", rank: "TypeRank", bin: "TypeBinName", inverte :return: list expression. - Example:: + Example: + + .. testcode:: # Remove the 2 largest elements from List bin "a". # Assume list bin contains [6, 12, 4, 21] @@ -721,7 +757,9 @@ def __init__( :return: list expression. - Example:: + Example: + + .. testcode:: # Remove the 3 smallest items from list bin "a". expr = exp.ListRemoveByRankRange(None, 0, 3, exp.ListBin("a")).compile() @@ -754,7 +792,9 @@ def __init__(self, ctx: "TypeCTX", bin: "TypeBinName"): :return: Integer expression. - Example:: + Example: + + .. testcode:: #Take the size of list bin "a". expr = exp.ListSize(None, exp.ListBin("a")).compile() @@ -793,7 +833,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the index of the element with value, 3, in list bin "a". expr = exp.ListGetByValue(None, aerospike.LIST_RETURN_INDEX, 3, exp.ListBin("a")).compile() @@ -839,7 +881,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get rank of values between 3 (inclusive) and 7 (exclusive) in list bin "a". expr = exp.ListGetByValueRange(None, aerospike.LIST_RETURN_RANK, 3, 7, exp.ListBin("a")).compile() @@ -882,7 +926,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the indexes of the the elements in list bin "a" with values [3, 6, 12]. expr = exp.ListGetByValueList(None, aerospike.LIST_RETURN_INDEX, [3, 6, 12], exp.ListBin("a")).compile() @@ -923,7 +969,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # [6, 12, 4, 21] expr = exp.ListGetByValueRelRankRangeToEnd(None, aerospike.LIST_RETURN_VALUE, 3, 1, @@ -993,7 +1041,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # [6, 12, 4, 21] expr = exp.ListGetByValueRelRankRange(None, aerospike.LIST_RETURN_VALUE, 3, 1, 2, @@ -1039,7 +1089,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the value at index 0 in list bin "a". (assume this value is an integer) expr = exp.ListGetByIndex(None, aerospike.LIST_RETURN_VALUE, exp.ResultType.INTEGER, 0, @@ -1079,7 +1131,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get element 5 to end from list bin "a". expr = exp.ListGetByIndexRangeToEnd(None, aerospike.LIST_RETURN_VALUE, 5, exp.ListBin("a")).compile() @@ -1122,7 +1176,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements at indexes 3, 4, 5, 6 in list bin "a". expr = exp.ListGetByIndexRange(None, aerospike.LIST_RETURN_VALUE, 3, 4, exp.ListBin("a")).compile() @@ -1163,7 +1219,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the smallest element in list bin "a". expr = exp.ListGetByRank(None, aerospike.LIST_RETURN_VALUE, exp.ResultType.INTEGER, 0, @@ -1196,7 +1254,9 @@ def __init__(self, ctx: "TypeCTX", return_type: int, rank: "TypeRank", bin: "Typ :return: Expression. - Example:: + Example: + + .. testcode:: # Get the three largest elements in list bin "a". expr = exp.ListGetByRankRangeToEnd(None, aerospike.LIST_RETURN_VALUE, -3, exp.ListBin("a")).compile() @@ -1238,7 +1298,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the 3 smallest elements in list bin "a". expr = exp.ListGetByRankRange(None, aerospike.LIST_RETURN_VALUE, 0, 3, exp.ListBin("a")).compile() diff --git a/aerospike_helpers/expressions/map.py b/aerospike_helpers/expressions/map.py index ac6623705f..cd9c08b1ec 100644 --- a/aerospike_helpers/expressions/map.py +++ b/aerospike_helpers/expressions/map.py @@ -62,7 +62,9 @@ def __init__(self, ctx: "TypeCTX", policy: "TypePolicy", key: "TypeKey", value: :return: Map expression. - Example:: + Example: + + .. testcode:: # Put {"key": 27} into map bin "b". expr = exp.MapPut(None, None, "key", 27, exp.MapBin("b")).compile() @@ -100,7 +102,9 @@ def __init__(self, ctx: "TypeCTX", policy: "TypePolicy", map: map, bin: "TypeBin :return: Map expression. - Example:: + Example: + + .. testcode:: # Put {27: 'key27', 28: 'key28'} into map bin "b". expr = exp.MapPutItems(None, None, {27: 'key27', 28: 'key28'}, exp.MapBin("b")).compile() @@ -140,7 +144,9 @@ def __init__(self, ctx: "TypeCTX", policy: "TypePolicy", key: "TypeKey", value: :return: Map expression. - Example:: + Example: + + .. testcode:: # Increment element at 'vageta' in map bin "b" by 9000. expr = exp.MapIncrement(None, None, 'vageta', 9000, exp.MapBin("b")).compile() @@ -176,7 +182,9 @@ def __init__(self, ctx: "TypeCTX", bin: "TypeBinName"): :return: Map expression. - Example:: + Example: + + .. testcode:: # Clear map bin "b". expr = exp.MapClear(None, exp.MapBin("b")).compile() @@ -203,7 +211,9 @@ def __init__(self, ctx: "TypeCTX", key: "TypeKey", bin: "TypeBinName"): :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove element at key 1 in map bin "b". expr = exp.MapRemoveByKey(None, 1, exp.MapBin("b")).compile() @@ -234,7 +244,9 @@ def __init__(self, ctx: "TypeCTX", keys: List[TypeKey], bin: "TypeBinName", inve :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove elements at keys [1, 2] in map bin "b". expr = exp.MapRemoveByKeyList(None, [1, 2], exp.MapBin("b")).compile() @@ -276,7 +288,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove elements at keys between 1 and 10 in map bin "b". expr = exp.MapRemoveByKeyRange(None, 1, 10, exp.MapBin("b")).compile() @@ -312,7 +326,9 @@ def __init__(self, ctx: "TypeCTX", key: "TypeKey", index: "TypeIndex", bin: "Typ :return: Map expression. - Example:: + Example: + + .. testcode:: # {"key1": 1, "key2": 2, "key3": 3, "key4": 10} expr = exp.MapRemoveByKeyRelIndexRangeToEnd(None, "key2", 1, exp.MapBin("b")).compile() @@ -355,7 +371,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove the next two items after key1 # {"key1": 1, "key2": 2, "key3": 3, "key4": 10} @@ -390,7 +408,9 @@ def __init__(self, ctx: "TypeCTX", value: "TypeValue", bin: "TypeBinName", inver :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove {"key1": 1} from map bin "b". expr = exp.MapRemoveByValue(None, 1, exp.MapBin("b")).compile() @@ -421,7 +441,9 @@ def __init__(self, ctx: "TypeCTX", values: "TypeListValue", bin: "TypeBinName", :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove elements with values 1, 2, 3 from map bin "b". expr = exp.MapRemoveByValueList(None, [1, 2, 3], exp.MapBin("b")).compile() @@ -463,7 +485,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove list of items with values >= 3 and < 7 from map bin "b". expr = exp.MapRemoveByValueRange(None, 3, 7, exp.MapBin("b")).compile() @@ -502,7 +526,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove all elements with values larger than 3 from map bin "b". expr = exp.MapRemoveByValueRelRankRangeToEnd(None, 3, 1, exp.MapBin("b")).compile() @@ -546,7 +572,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove the key with a value just lower than 17 expr = exp.MapRemoveByValueRelRankRange(None, 17, -1, 1, exp.MapBin("b")).compile() @@ -578,7 +606,9 @@ def __init__(self, ctx: "TypeCTX", index: "TypeIndex", bin: "TypeBinName"): :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove element with smallest key from map bin "b". expr = exp.MapRemoveByIndex(None, 0, exp.MapBin("b")).compile() @@ -609,7 +639,9 @@ def __init__(self, ctx: "TypeCTX", index: "TypeIndex", bin: "TypeBinName", inver :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove all elements starting from index 3 in map bin "b". expr = exp.MapRemoveByIndexRangeToEnd(None, 3, exp.MapBin("b")).compile() @@ -648,7 +680,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Get size of map bin "b" after index 3, 4, and 5 have been removed. expr = exp.MapSize(None, exp.MapRemoveByIndexRange(None, 3, 3, exp.MapBin("b"))).compile() @@ -679,7 +713,9 @@ def __init__(self, ctx: "TypeCTX", rank: "TypeRank", bin: "TypeBinName"): :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove key with smallest value in map bin "b". expr = exp.MapRemoveByRank(None, 0, exp.MapBin("b")).compile() @@ -710,7 +746,9 @@ def __init__(self, ctx: "TypeCTX", rank: "TypeRank", bin: "TypeBinName", inverte :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove keys with 2 largest values from map bin "b". expr = exp.MapRemoveByRankRangeToEnd(None, -2, exp.MapBin("b")).compile() @@ -749,7 +787,9 @@ def __init__( :return: Map expression. - Example:: + Example: + + .. testcode:: # Remove 3 keys with the smallest values from map bin "b". expr = exp.MapRemoveByRankRange(None, 0, 3, exp.MapBin("b")).compile() @@ -784,7 +824,9 @@ def __init__(self, ctx: "TypeCTX", bin: "TypeBinName"): :return: Integer expression. - Example:: + Example: + + .. testcode:: #Take the size of map bin "b". expr = exp.MapSize(None, exp.MapBin("b")).compile() @@ -816,7 +858,9 @@ def __init__(self, ctx: "TypeCTX", return_type: int, value_type: int, key: "Type :return: Expression. - Example:: + Example: + + .. testcode:: # Get the value at key "key0" in map bin "b". (assume the value at key0 is an integer) expr = exp.MapGetByKey(None, aerospike.MAP_RETURN_VALUE, exp.ResultType.INTEGER, "key0", @@ -863,7 +907,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements at keys "key3", "key4", "key5", "key6" in map bin "b". expr = exp.MapGetByKeyRange(None, aerospike.MAP_RETURN_VALUE, "key3", "key7", exp.MapBin("b")).compile() @@ -908,7 +954,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements at keys "key3", "key4", "key5" in map bin "b". expr = exp.MapGetByKeyList(None, aerospike.MAP_RETURN_VALUE, ["key3", "key4", "key5"], @@ -955,7 +1003,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements with keys larger than "key2" from map bin "b". expr = exp.MapGetByKeyRelIndexRangeToEnd(None, aerospike.MAP_RETURN_VALUE, "key2", 1, @@ -1005,7 +1055,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: expr = exp.MapGetByKeyRelIndexRange(None, aerospike.MAP_RETURN_VALUE, "key2", 0, 2, exp.MapBin("b")).compile() @@ -1056,7 +1108,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the rank of the element with value, 3, in map bin "b". expr = exp.MapGetByValue(None, aerospike.MAP_RETURN_RANK, 3, exp.MapBin("b")).compile() @@ -1101,7 +1155,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements with values between 3 and 7 from map bin "b". expr = exp.MapGetByValueRange(None, aerospike.MAP_RETURN_VALUE, 3, 7, exp.MapBin("b")).compile() @@ -1145,7 +1201,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the indexes of the the elements in map bin "b" with values [3, 6, 12]. expr = exp.MapGetByValueList(None, aerospike.MAP_RETURN_INDEX, [3, 6, 12], exp.MapBin("b")).compile() @@ -1188,7 +1246,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the values of all elements in map bin "b" larger than 3. expr = exp.MapGetByValueRelRankRangeToEnd(None, aerospike.MAP_RETURN_VALUE, 3, 1, exp.MapBin("b")).compile() @@ -1233,7 +1293,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # {"key1": 1, "key2": 2, "key3": 3, "key4": 10} # Get next two largest values greater than a value of 1 @@ -1276,7 +1338,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the value at index 0 in map bin "b". (assume this value is an integer) expr = exp.MapGetByIndex(None, aerospike.MAP_RETURN_VALUE, @@ -1316,7 +1380,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get element at index 5 to end from map bin "b". expr = exp.MapGetByIndexRangeToEnd(None, aerospike.MAP_RETURN_VALUE, 5, exp.MapBin("b")).compile() @@ -1359,7 +1425,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get elements at indexes 3, 4, 5, 6 in map bin "b". expr = exp.MapGetByIndexRange(None, aerospike.MAP_RETURN_VALUE, 3, 4, exp.MapBin("b")).compile() @@ -1400,7 +1468,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the smallest element in map bin "b". expr = exp.MapGetByRank(None, aerospike.MAP_RETURN_VALUE, exp.ResultType.INTEGER, 0, @@ -1433,10 +1503,12 @@ def __init__(self, ctx: "TypeCTX", return_type: int, rank: "TypeRank", bin: "Typ :return: Expression. - Example:: + Example: + + .. testcode:: # Get the three largest elements in map bin "b". - expr = exp.MapGetByRankRangeToEnd(None, aerospike.MAP_RETURN_VALUE, -3, MapBin("b")).compile() + expr = exp.MapGetByRankRangeToEnd(None, aerospike.MAP_RETURN_VALUE, -3, exp.MapBin("b")).compile() """ self._children = (rank, bin if isinstance(bin, _BaseExpr) else MapBin(bin)) self._fixed = {_Keys.RETURN_TYPE_KEY: return_type} @@ -1476,7 +1548,9 @@ def __init__( :return: Expression. - Example:: + Example: + + .. testcode:: # Get the 3 smallest elements in map bin "b". expr = exp.MapGetByRankRange(None, aerospike.MAP_RETURN_VALUE, 0, 3, exp.MapBin("b")).compile() diff --git a/aerospike_helpers/metrics/__init__.py b/aerospike_helpers/metrics/__init__.py index 2f5ceb5c87..a64a624ccb 100644 --- a/aerospike_helpers/metrics/__init__.py +++ b/aerospike_helpers/metrics/__init__.py @@ -217,7 +217,9 @@ class MetricsPolicy: The bucket units are in milliseconds. The first 2 buckets are "<=1ms" and ">1ms". labels (dict[str, str]): List of name/value labels that is applied when exporting metrics. - Example:: + Example: + + .. testcode:: # latencyColumns=7 latencyShift=1 # <=1ms >1ms >2ms >4ms >8ms >16ms >32ms diff --git a/aerospike_helpers/operations/bitwise_operations.py b/aerospike_helpers/operations/bitwise_operations.py index f0677bbe28..a4182a338d 100644 --- a/aerospike_helpers/operations/bitwise_operations.py +++ b/aerospike_helpers/operations/bitwise_operations.py @@ -30,7 +30,9 @@ * -1: rightmost bit in the map * -4: 3 bits from rightmost -Example:: +Example: + +.. testcode:: import aerospike from aerospike_helpers.operations import bitwise_operations @@ -52,13 +54,11 @@ _, _, bins = client.get(key) print("5 bytes: ", bins) - # 5 bytes: {'bitwise1': b'\x01\x01\x01\x01\x01'} _, _, _ = client.operate(key, ops) _, _, newbins = client.get(key) print("After resize to 10 bytes: ", newbins) - # After resize to 10 bytes: {'bitwise1': b'\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00'} # EXAMPLE 2: shrink the five_ones bin to a bytesize of 5 from the front. @@ -71,13 +71,20 @@ _, _, _ = client.operate(key, ops) _, _, newbins = client.get(key) print("After resize to 5 bytes again: ", newbins) - # After resize to 5 bytes again: {'bitwise1': b'\x00\x00\x00\x00\x00'} # Cleanup and close the connection to the Aerospike cluster. client.remove(key) client.close() -Example:: +.. testoutput:: + + 5 bytes: {'bitwise1': b'\\x01\\x01\\x01\\x01\\x01'} + After resize to 10 bytes: {'bitwise1': b'\\x01\\x01\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00'} + After resize to 5 bytes again: {'bitwise1': b'\\x00\\x00\\x00\\x00\\x00'} + +Example: + +.. testcode:: import aerospike from aerospike import exception as e @@ -106,7 +113,6 @@ ] _, _, results = client.operate(key, ops) print(results) - # {'bitwise1': b'\x01\x01\x01\x01\x01'} # Example 2: modify bits using the 'or' op, then read bits # 0 = offset @@ -119,7 +125,6 @@ ] _, _, results = client.operate(key, ops) print(results) - # {'bitwise1': b'\xff\x01\x01\x01\x01'} # Example 3: modify bits using the 'remove' op, then read bits' # offset = 0 @@ -131,10 +136,15 @@ ] _, _, results = client.operate(key, ops) print(results) - # {'bitwise1': b'\x01\x01\x01'} client.close() +.. testoutput:: + + {'bitwise1': b'\\x01\\x01\\x01\\x01\\x01'} + {'bitwise1': b'\\xff\\x01\\x01\\x01\\x01'} + {'bitwise1': b'\\x01\\x01\\x01'} + .. seealso:: `Bits (Data Types) `_. """ import aerospike diff --git a/aerospike_helpers/operations/expression_operations.py b/aerospike_helpers/operations/expression_operations.py index da5ec131ab..ae4b55555f 100644 --- a/aerospike_helpers/operations/expression_operations.py +++ b/aerospike_helpers/operations/expression_operations.py @@ -47,15 +47,16 @@ def expression_read(bin_name: str, expression: resources._BaseExpr, expression_r Returns: A dictionary to be passed to operate or operate_ordered. - Example:: + Example: - # Read the value of int bin "balance". - # Let 'client' be a connected aerospike client. - # Let int bin 'balance' == 50. + .. testcode:: from aerospike_helpers.operations import expression_operations as expressions from aerospike_helpers.expressions import * + # Read the value of int bin "balance". + # Let 'client' be a connected aerospike client. + # Let int bin 'balance' == 50. expr = IntBin("balance").compile() ops = [ expressions.expression_read("balance", expr) @@ -63,7 +64,10 @@ def expression_read(bin_name: str, expression: resources._BaseExpr, expression_r _, _, res = client.operate(self.key, ops) print(res) - # EXPECTED OUTPUT: {"balance": 50} + .. testoutput:: + + {"balance": 50} + """ op_dict = { @@ -89,24 +93,29 @@ def expression_write(bin_name: str, expression: resources._BaseExpr, expression_ Returns: A dictionary to be passed to operate or operate_ordered. - Example:: + Example: + + .. testcode:: + + from aerospike_helpers.operations import expression_operations as expr_ops + from aerospike_helpers.expressions import * # Write the value of int bin "balance" + 50 back to "balance". # Let 'client' be a connected aerospike client. # Let int bin 'balance' == 50. - from aerospike_helpers.operations import expression_operations as expressions - from aerospike_helpers.expressions import * - expr = Add(IntBin("balance"), 50).compile() ops = [ - expressions.expression_write("balance", expr) + expr_ops.expression_write("balance", expr) ] client.operate(self.key, ops) _, _, res = client.get(self.key) print(res) - # EXPECTED OUTPUT: {"balance": 100} + .. testoutput:: + + {"balance": 100} + """ op_dict = { diff --git a/aerospike_helpers/operations/hll_operations.py b/aerospike_helpers/operations/hll_operations.py index 7e91fbcc8b..40ebcd804b 100644 --- a/aerospike_helpers/operations/hll_operations.py +++ b/aerospike_helpers/operations/hll_operations.py @@ -29,7 +29,9 @@ .. seealso:: `HyperLogLog (Data Type) more info. \ `_. -Example:: +Example: + +.. testcode:: import aerospike from aerospike_helpers.operations import hll_operations as hll_ops @@ -78,24 +80,30 @@ # Pass in Amy's key _, _, res = client.operate(keys[0], ops) print("Estimated items viewed intersection:", res["viewed"]) - # Estimated items viewed intersection: 251 - # Actual intersection: 250 + print("Actual intersection: 250") # Find out how many unique products Amy, Farnsworth, and Scruffy have viewed. ops = [hll_ops.hll_get_union_count("viewed", viewed)] _, _, res = client.operate(keys[0], ops) print("Estimated items viewed union:", res["viewed"]) - # Estimated items viewed union: 1010 - # Actual union: 1000 + print("Actual union: 1000") # Find the similarity of Amy, Farnsworth, and Scruffy's product views. ops = [hll_ops.hll_get_similarity("viewed", viewed)] _, _, res = client.operate(keys[0], ops) print("Estimated items viewed similarity: %f%%" % (res["viewed"] * 100)) - # Estimated items viewed similarity: 24.888393% - # Actual similarity: 25% + print("Actual similarity: 25%") + +.. testoutput:: + + Estimated items viewed intersection: 251 + Actual intersection: 250 + Estimated items viewed union: 1010 + Actual union: 1000 + Estimated items viewed similarity: 24.888393% + Actual similarity: 25% """ diff --git a/doc/aerospike.rst b/doc/aerospike.rst index 3e4571a7c4..ceb2409b80 100644 --- a/doc/aerospike.rst +++ b/doc/aerospike.rst @@ -45,16 +45,15 @@ Client Simple example: - .. code-block:: python + .. testcode:: import aerospike - # Configure the client to first connect to a cluster node at 127.0.0.1 # The client will learn about the other nodes in the cluster from the seed node. # Also sets a top level policy for read commands config = { - 'hosts': [ ('127.0.0.1', 3000) ], - 'policies': {'read': {'total_timeout': 1000}}, + 'hosts': [ ('127.0.0.1', 3000) ], + 'policies': {'read': {'total_timeout': 1000}} } client = aerospike.client(config) @@ -65,8 +64,6 @@ Client import aerospike import sys - # NOTE: Use of TLS requires Aerospike Enterprise version >= 3.11 - # and client version 2.1.0 or greater tls_name = "some-server-tls-name" tls_ip = "127.0.0.1" tls_port = 4333 @@ -103,15 +100,14 @@ Geospatial :param dict geo_data: a :class:`dict` representing the geospatial data. :return: an instance of the :py:class:`aerospike.GeoJSON` class. - .. code-block:: python + .. testcode:: import aerospike # Create GeoJSON point using WGS84 coordinates. latitude = 45.920278 longitude = 63.342222 - loc = aerospike.geodata({'type': 'Point', - 'coordinates': [longitude, latitude]}) + loc = aerospike.geodata({'type': 'Point', 'coordinates': [longitude, latitude]}) .. versionadded:: 1.0.54 @@ -123,7 +119,7 @@ Geospatial :param dict geojson_str: a :class:`str` of raw GeoJSON. :return: an instance of the :py:class:`aerospike.GeoJSON` class. - .. code-block:: python + .. testcode:: import aerospike @@ -152,7 +148,7 @@ Types :return: a type representing a wildcard value. - .. code-block:: python + .. testcode:: import aerospike from aerospike_helpers.operations import list_operations as list_ops @@ -160,11 +156,16 @@ Types client = aerospike.client({'hosts': [('localhost', 3000)]}) key = 'test', 'demo', 1 + client.put(key, bins={"list_bin": [[1, 2, 3], [2, 3, 4], [1, 'a']]}) + # get all values of the form [1, ...] from a list of lists. - # For example if list is [[1, 2, 3], [2, 3, 4], [1, 'a']], this operation will match - # [1, 2, 3] and [1, 'a'] operations = [list_ops.list_get_by_value('list_bin', [1, aerospike.CDTWildcard()], aerospike.LIST_RETURN_VALUE)] _, _, bins = client.operate(key, operations) + print(bins["list_bin"]) + + .. testoutput:: + + [[1, 2, 3], [1, 'a']] .. versionadded:: 3.5.0 .. note:: This requires Aerospike Server 4.3.1.3 or greater @@ -176,7 +177,7 @@ Types :return: a type representing an infinite value. - .. code-block:: python + .. testcode:: import aerospike from aerospike_helpers.operations import list_operations as list_ops @@ -184,11 +185,16 @@ Types client = aerospike.client({'hosts': [('localhost', 3000)]}) key = 'test', 'demo', 1 + client.put(key, bins={"list_bin": [[1, 2, 3], [2, 3, 4], [1, 'a']]}) + # get all values of the form [1, ...] from a list of lists. - # For example if list is [[1, 2, 3], [2, 3, 4], [1, 'a']], this operation will match - # [1, 2, 3] and [1, 'a'] operations = [list_ops.list_get_by_value_range('list_bin', aerospike.LIST_RETURN_VALUE, [1], [1, aerospike.CDTInfinite()])] _, _, bins = client.operate(key, operations) + print(bins["list_bin"]) + + .. testoutput:: + + [[1, 2, 3], [1, 'a']] .. versionadded:: 3.5.0 .. note:: This requires Aerospike Server 4.3.1.3 or greater @@ -214,10 +220,10 @@ Serialization .. seealso:: To use this function with :meth:`Client.put`, \ the argument to the serializer parameter should be :const:`aerospike.SERIALIZER_USER`. - .. code-block:: python + .. testcode:: def my_serializer(val): - return json.dumps(val) + return json.dumps(val) aerospike.set_serializer(my_serializer) @@ -336,13 +342,17 @@ Other :return: a RIPEMD-160 digest of the input tuple. :rtype: :class:`bytearray` - .. code-block:: python + .. testcode:: import aerospike import pprint - digest = aerospike.calc_digest("test", "demo", 1 ) - pp.pprint(digest) + digest = aerospike.calc_digest("test", "demo", 1) + pprint.pprint(digest) + + .. testoutput:: + + bytearray(b'\xb7\xf4\xb88\x89\xe2\xdag\xdeh>\x1d\xf6\x91\x9a\x1e\xac\xc4F\xc8') .. _client_config: @@ -374,48 +384,52 @@ Only the `hosts` key is required; the rest of the keys are optional. Invalid client config example: - .. code-block:: python + .. testcode:: import aerospike config = { - "validate_keys": True, - "hosts": [ - ("127.0.0.1", 3000) - ], - # The correct key is "user", but "username" may be used by accident - "username": "user", - "password": "password" + "validate_keys": True, + "hosts": [ + ("127.0.0.1", 3000) + ], + # The correct key is "user", but "username" may be used by accident + "username": "user", + "password": "password" } - # This call will raise a ParamError from aerospike.exception - # Exception message should be: - # "username" is an invalid client config dictionary key client = aerospike.client(config) + .. testoutput:: + + Traceback (most recent call last): + aerospike.exception.ParamError: "username" is an invalid client config dictionary key + Invalid policy example: - .. code-block:: python + .. testcode:: import aerospike config = { - "validate_keys": True, - "hosts": [ - ("127.0.0.1", 3000) - ], + "validate_keys": True, + "hosts": [ + ("127.0.0.1", 3000) + ], } client = aerospike.client(config) key = ("test", "demo", 1) # "key_policy" is used instead of the correct key named "key" policy = { - "key_policy": aerospike.POLICY_KEY_SEND + "key_policy": aerospike.POLICY_KEY_SEND } - # This call will raise a ParamError from aerospike.exception - # Exception message should be: - # "key_policy" is an invalid policy dictionary key client.get(key, policy=policy) + .. testoutput:: + + Traceback (most recent call last): + aerospike.exception.ParamError: "key_policy" is an invalid policy dictionary key + * **hosts** (:class:`list`) A list of tuples identifying a node (or multiple nodes) in the cluster. diff --git a/doc/aerospike_helpers.expressions.rst b/doc/aerospike_helpers.expressions.rst index 53e3fcfbf3..b32f11690f 100644 --- a/doc/aerospike_helpers.expressions.rst +++ b/doc/aerospike_helpers.expressions.rst @@ -157,7 +157,9 @@ The following documentation uses type aliases that map to standard Python types. .. note:: Requires server version >= 5.2.0 -Assume all in-line examples run this code beforehand:: +Assume all in-line examples run this code beforehand: + +.. testsetup:: import aerospike import aerospike_helpers.expressions as exp diff --git a/doc/client.rst b/doc/client.rst index 329ab109b7..b8513e4859 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -31,8 +31,29 @@ Assume every in-line example runs this code beforehand: .. warning:: Only run example code on a brand new Aerospike server. This code deletes all records in the ``demo`` set! -.. include:: examples/boilerplate.py - :code: python + +.. testsetup:: + + # Imports + import aerospike + from aerospike import exception as ex + import sys + + # Configure the client + config = { + 'hosts': [ ('127.0.0.1', 3000)] + } + + # Create a client and connect it to the cluster + try: + client = aerospike.client(config) + client.truncate('test', "demo", 0) + except ex.ClientError as e: + print("Error: {0} [{1}]".format(e.msg, e.code)) + sys.exit(1) + + # Record key tuple: (namespace, set, key) + keyTuple = ('test', 'demo', 'key') Basic example: @@ -434,12 +455,16 @@ String Operations :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python - client.put(keyTuple, {'bin1': 'Martin Luther King'}) - client.append(keyTuple, 'bin1', ' jr.') - (_, _, bins) = client.get(keyTuple) - print(bins) # Martin Luther King jr. + .. doctest:: + + >>> client.put(keyTuple, {'bin1': 'Martin Luther King'}) + 0 + >>> client.append(keyTuple, 'bin1', ' jr.') + 0 + >>> (_, _, bins) = client.get(keyTuple) + >>> print(bins) + {'bin1': 'Martin Luther King jr.'} .. method:: prepend(key, bin, val[, meta: dict[, policy: dict]]) @@ -455,12 +480,16 @@ String Operations :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python + .. testcode:: client.put(keyTuple, {'bin1': 'Freeman'}) - client.prepend(keyTuple, 'bin1', ' Gordon ') + client.prepend(keyTuple, 'bin1', 'Gordon ') (_, _, bins) = client.get(keyTuple) - print(bins) # Gordon Freeman + print(bins) + + .. testoutput:: + + {'bin1': 'Gordon Freeman'} .. index:: single: Numeric Operations @@ -486,7 +515,7 @@ Numeric Operations :param dict policy: optional :ref:`aerospike_operate_policies`. Note: the ``exists`` policy option may not be: ``aerospike.POLICY_EXISTS_CREATE_OR_REPLACE`` nor ``aerospike.POLICY_EXISTS_REPLACE`` :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python + .. testcode:: # Start with 100 lives client.put(keyTuple, {'lives': 100}) @@ -494,12 +523,17 @@ Numeric Operations # Gain health client.increment(keyTuple, 'lives', 10) (key, meta, bins) = client.get(keyTuple) - print(bins) # 110 + print("Lives:", bins["lives"]) # Take damage client.increment(keyTuple, 'lives', -90) (key, meta, bins) = client.get(keyTuple) - print(bins) # 20 + print("Lives:", bins["lives"]) + + .. testoutput:: + + Lives: 110 + Lives: 20 .. index:: single: List Operations @@ -557,6 +591,30 @@ Transactions User Defined Functions ---------------------- +.. testcode:: udf + + import aerospike + + config = { + 'hosts': [ ('127.0.0.1', 3000)], + 'lua': { 'user_path': '~/lua-scripts/'} + } + client = aerospike.client(config) + # Register the UDF module and copy it to the Lua 'user_path' + client.udf_put('./examples/scan/my_udf.lua') + + print("Before remove:", client.udf_list()) + + client.udf_remove('my_udf.lua') + print("After remove:", client.udf_list()) + + client.close() + +.. testoutput:: udf + + Before remove: [{'content': bytearray(b'...'), 'hash': bytearray(b'...'), 'name': 'my_udf.lua', 'type': 0}] + After remove: [] + .. class:: Client :noindex: @@ -574,19 +632,9 @@ User Defined Functions .. note:: To run this example, do not run the boilerplate code. - .. code-block:: python - :emphasize-lines: 5,9 - - import aerospike + .. TODO - probably there is better syntax than using emphasize-lines with hardcoded numbers - config = { - 'hosts': [ ('127.0.0.1', 3000)], - 'lua': { 'user_path': '/path/to/lua/user_path'} - } - client = aerospike.client(config) - # Register the UDF module and copy it to the Lua 'user_path' - client.udf_put('/path/to/my_module.lua') - client.close() + .. :emphasize-lines: 5,9 .. method:: udf_remove(module[, policy: dict]) @@ -598,10 +646,6 @@ User Defined Functions :param dict policy: currently **timeout** in milliseconds is the available policy. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python - - client.udf_remove('my_module.lua') - .. method:: udf_list([policy: dict]) -> [] Return the list of UDF modules registered with the cluster. @@ -610,20 +654,6 @@ User Defined Functions :rtype: :class:`list` :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python - - print(client.udf_list()) - # [ - # {'content': bytearray(b''), - # 'hash': bytearray(b'195e39ceb51c110950bd'), - # 'name': 'my_udf1.lua', - # 'type': 0}, - # {'content': bytearray(b''), - # 'hash': bytearray(b'8a2528e8475271877b3b'), - # 'name': 'stream_udf.lua', - # 'type': 0} - # ] - .. method:: udf_get(module: str[, language: int = aerospike.UDF_TYPE_LUA[, policy: dict]]) -> str Return the content of a UDF module which is registered with the cluster. @@ -718,12 +748,15 @@ Info Operations :return: a :class:`list` of node info dictionaries. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python + .. testcode:: # Assuming two nodes nodes = client.get_node_names() print(nodes) - # [{'address': '1.1.1.1', 'port': 3000, 'node_name': 'BCER199932C'}, {'address': '1.1.1.1', 'port': 3010, 'node_name': 'ADFFE7782CD'}] + + .. testoutput:: + + [{'address': '...', 'port': ..., 'node_name': '...'}...] .. versionchanged:: 6.0.0 @@ -734,12 +767,15 @@ Info Operations :return: a :class:`list` of node address tuples. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python + .. testcode:: # Assuming two nodes nodes = client.get_nodes() print(nodes) - # [('127.0.0.1', 3000), ('127.0.0.1', 3010)] + + .. testoutput:: + + [('127.0.0.1', 3000)...] .. versionchanged:: 3.0.0 @@ -768,11 +804,14 @@ Info Operations :rtype: :class:`dict` :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. code-block:: python + .. testcode:: response = client.info_all("namespaces") print(response) - # {'BB9020011AC4202': (None, 'test\n')} + + .. testoutput:: + + {'...': (None, 'test\n')} .. versionadded:: 3.0.0 @@ -917,7 +956,7 @@ Index Operations .. note:: Requires server version >= 3.8.0 - .. code-block:: python + .. testcode:: import aerospike @@ -1038,9 +1077,7 @@ Index Operations .. note:: Requires server version >= 3.7.0 - .. code-block:: python - - import aerospike + .. testcode:: client = aerospike.client({ 'hosts': [ ('127.0.0.1', 3000)]}) client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') @@ -1449,7 +1486,7 @@ Key Tuple * How to use the key tuple in a `put` operation * How to fetch the key tuple in a `get` operation - .. code-block:: python + .. testcode:: import aerospike @@ -1465,7 +1502,7 @@ Key Tuple keyTuple = (namespaceName, setName, primaryKeyName) # Insert a record - recordBins = {'bin1':0, 'bin2':1} + recordBins = {'bin1': 0, 'bin2': 1} client.put(keyTuple, recordBins) # Now fetch that record @@ -1476,13 +1513,14 @@ Key Tuple # and there is the record's digest print(key) - # Expected output: - # ('test', 'setname', None, bytearray(b'b\xc7[\xbb\xa4K\xe2\x9al\xd12!&\xbf<\xd9\xf9\x1bPo')) - # Cleanup client.remove(keyTuple) client.close() + .. testoutput:: + + ('test', 'setname', None, bytearray(b'b\xc7[\xbb\xa4K\xe2\x9al\xd12!&\xbf<\xd9\xf9\x1bPo')) + .. seealso:: `Data Model: Keys and Digests `_. .. _aerospike_record_tuple: @@ -1515,7 +1553,7 @@ Record Tuple We reuse the code example in the key-tuple section and print the ``meta`` and ``bins`` values that were returned from :meth:`~aerospike.Client.get()`: - .. code-block:: python + .. testcode:: import aerospike @@ -1530,25 +1568,27 @@ Record Tuple keyTuple = (namespaceName, setName, primaryKeyName) # Insert a record - recordBins = {'bin1':0, 'bin2':1} + recordBins = {'bin1': 0, 'bin2': 1} client.put(keyTuple, recordBins) # Now fetch that record (key, meta, bins) = client.get(keyTuple) # Generation is 1 because this is the first time we wrote the record - print(meta) - - # Expected output: - # {'ttl': 2592000, 'gen': 1} + print("Metadata:", meta) # The bin-value pairs we inserted - print(bins) - {'bin1': 0, 'bin2': 1} + print("Bins:", bins) client.remove(keyTuple) client.close() + .. testoutput:: + + Metadata: {'ttl': 2592000, 'gen': 1} + Bins: {'bin1': 0, 'bin2': 1} + + .. seealso:: `Data Model: Records `_. .. _metadata_dict: @@ -2300,7 +2340,7 @@ List Policies Example: - .. code-block:: python + .. testcode:: list_policy = { "write_flags": aerospike.LIST_WRITE_ADD_UNIQUE | aerospike.LIST_WRITE_INSERT_BOUNDED, @@ -2345,7 +2385,7 @@ Map Policies Example: - .. code-block:: python + .. testcode:: # Server >= 4.3.0 map_policy = { @@ -2375,7 +2415,7 @@ Bit Policies Example: - .. code-block:: python + .. testcode:: bit_policy = { 'bit_write_flags': aerospike.BIT_WRITE_UPDATE_ONLY @@ -2403,7 +2443,7 @@ HyperLogLog Policies Example: - .. code-block:: python + .. testcode:: HLL_policy = { 'flags': aerospike.HLL_WRITE_UPDATE_ONLY @@ -2487,6 +2527,8 @@ Partition Objects Default: ``{}`` (All partitions will be queried/scanned). + .. TODO more thorough example needed here. + .. code-block:: python # Example of a query policy using partition_filter. diff --git a/doc/conf.py b/doc/conf.py index c015fe4626..94c23ce51d 100755 --- a/doc/conf.py +++ b/doc/conf.py @@ -2,14 +2,14 @@ import sys, os -try: - from unittest.mock import MagicMock -except ImportError: - try: - from mock import Mock as MagicMock - except ImportError as e: - print("mock is missing: pip install mock") - raise e +# try: +# from unittest.mock import MagicMock +# except ImportError: +# try: +# from mock import Mock as MagicMock +# except ImportError as e: +# print("mock is missing: pip install mock") +# raise e # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -20,13 +20,16 @@ # see https://docs.readthedocs.io/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules -class Mock(MagicMock): - @classmethod - def __getattr__(cls, name): - return MagicMock() +# class Mock(MagicMock): +# @classmethod +# def __getattr__(cls, name): +# return MagicMock() -sys.modules.update({"aerospike": Mock()}) +try: + import aerospike +except ImportError: + autodoc_mock_imports = ["aerospike"] # sys.path.append(os.path.abspath('/usr/local/lib/python2.7/site-packages/aerospike-1.0.44-py2.7-macosx-10.9-x86_64.egg/')) @@ -37,13 +40,17 @@ def __getattr__(cls, name): extensions = [ "sphinx.ext.todo", "sphinx.ext.autodoc", + "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.napoleon", - "sphinxcontrib.spelling" + "sphinxcontrib.spelling", + "sphinx_copybutton" ] napoleon_google_docstring = True intersphinx_mapping = {"python": ("https://docs.python.org/3", None)} +copybutton_exclude = '.linenos, .gp' + # Add any paths that contain templates here, relative to this directory. templates_path = [] diff --git a/doc/examples/boilerplate.py b/doc/examples/boilerplate.py deleted file mode 100644 index 74a7adff80..0000000000 --- a/doc/examples/boilerplate.py +++ /dev/null @@ -1,20 +0,0 @@ -# Imports -import aerospike -from aerospike import exception as ex -import sys - -# Configure the client -config = { - 'hosts': [ ('127.0.0.1', 3000)] -} - -# Create a client and connect it to the cluster -try: - client = aerospike.client(config) - client.truncate('test', "demo", 0) -except ex.ClientError as e: - print("Error: {0} [{1}]".format(e.msg, e.code)) - sys.exit(1) - -# Record key tuple: (namespace, set, key) -keyTuple = ('test', 'demo', 'key') diff --git a/doc/requirements.txt b/doc/requirements.txt index 4662a72484..da5efab381 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -2,6 +2,7 @@ sphinx==9.1.0 sphinx-rtd-theme==3.1.0 sphinxcontrib-spelling==8.0.2 +sphinx-copybutton==0.5.2 certifi>=2023.7.22 # not directly required, pinned by Snyk to avoid a vulnerability jinja2>=3.1.3 # not directly required, pinned by Snyk to avoid a vulnerability pygments>=2.15.0 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/src/main/client/operate.c b/src/main/client/operate.c index b743252b83..c83daa99dd 100644 --- a/src/main/client/operate.c +++ b/src/main/client/operate.c @@ -1480,8 +1480,22 @@ static as_status get_operation(as_error *err, PyObject *op_dict, "Operation must contain an \"op\" entry"); } if (!PyLong_Check(py_operation)) { + PyTypeObject *py_op_type = Py_TYPE(py_operation); + if (!py_op_type) { + return as_error_update(err, AEROSPIKE_ERR_PARAM, + "Operation must be an integer, but got an " + "indeterminate type instead"); + } + const char *op_type_name = py_op_type->tp_name; + if (!op_type_name) { + return as_error_update(err, AEROSPIKE_ERR_PARAM, + "Operation must be an integer, but got an " + "indeterminate type instead"); + } return as_error_update(err, AEROSPIKE_ERR_PARAM, - "Operation must be an integer"); + "Operation must be an integer, but got a value " + "with type %s instead", + op_type_name); } *operation_ptr = PyLong_AsLong(py_operation);