Skip to main content

A ClI for Neo4j

Project description

lom

A command-line tool for Neo4j with an interactive shell that can be used by people and by AI agents. Connect to a Neo4j database and the Neo4j Aura management API from a single binary — run Cypher queries, manage cloud instances, and perform administrative operations.


Contents


Getting started

Prerequisites

  • Go 1.24 or later

Build

git clone <repo-url>
cd go-cli-tool
go build -o bin/lom ./cmd/lom

Run

# Run a subcommand directly
./bin/lom cypher "MATCH (n:Person) RETURN n.name LIMIT 5"
./bin/lom cloud instances list
./bin/lom admin show-databases
./bin/lom config list

# Point at a specific config file
./bin/lom --config-file ~/.lom/config.json cloud instances list

# Control output format
./bin/lom cypher --format json "MATCH (n) RETURN n LIMIT 10"
./bin/lom cloud instances list --format json
./bin/lom cloud instances list --format toon

Commands

All functionality is exposed as top-level subcommands. Running lom with no arguments prints help.

Subcommand Description
cypher [query] Execute a Cypher query against the connected database
cloud Manage Neo4j Aura cloud resources
admin Administrative operations against the connected database
config Manage CLI configuration

cypher

Executes a Cypher query against the connected database.

lom cypher "MATCH (n) RETURN n LIMIT 5"
lom cypher --param name=Alice "MATCH (n:Person {name:\$name}) RETURN n"
lom cypher --format json "MATCH (n) RETURN n"
lom cypher --format toon "MATCH (n)-[r]->(m) RETURN n,r,m"
lom cypher --limit 100 "MATCH (n) RETURN n"

Flags (placed before the query):

Flag Description
--param key=value Add a query parameter (repeatable). Values are auto-typed: int, float, bool, string.
--format table|toon|json|pretty-json|graph Override the output format for this query.
--limit N Override the auto-injected row limit.

Requires a Neo4j connection. If credentials are not configured, you are prompted to enter them on first use and they are saved to the config file.

cloud

Manages Neo4j Aura cloud resources.

Requires Aura credentials. If aura.client_id or aura.client_secret are not configured, you are prompted to enter them on first use.

lom cloud instances list
lom cloud instances ls                                                  # alias
lom cloud instances get <id>
lom cloud instances create name=<n> tenant=<id> [cloud=<p>] [region=<r>] [type=<t>] [version=<v>] [memory=<size>]
lom cloud instances update <id> [name=<new-name>] [memory=<size>]
lom cloud instances pause <id>
lom cloud instances resume <id>
lom cloud instances delete <id>
lom cloud instances rm <id>                                             # alias

lom cloud projects list
lom cloud projects get <id>

instances create requires name and tenant. All other fields fall back to aura.instance_defaults in the config. Set defaults to avoid repeating them on every invocation:

lom config set aura.instance_defaults.tenant_id abc-123
lom config set aura.instance_defaults.cloud_provider aws
lom cloud instances create name=my-db

Save your password. When instances create succeeds, the initial password is shown exactly once and cannot be recovered.

admin

Runs administrative commands against the connected database.

Requires a Neo4j connection. Same prerequisite as cypher.

lom admin show-users
lom admin show-databases

config

Manages CLI configuration. Changes made with set, delete, and reset are persisted to the config file immediately and take effect in the current session.

lom config list                                # show all keys, values, and descriptions
lom config list --format json
lom config set neo4j.uri bolt://myhost:7687
lom config set cypher.output_format json
lom config set aura.instance_defaults.region us-east-1
lom config delete neo4j.password              # reset a key to its default (prompts)
lom config reset                              # wipe config file, restore all defaults (prompts)

Configuration

Settings are resolved in this order, highest priority first:

CLI flags  >  environment variables  >  config file  >  defaults

Config file

The default config file path is ~/.lom/config.json. The directory and file are created automatically when credentials are first saved via an interactive prompt. Pass --config-file <path> to use a different location.

A full example:

{
  "log_level": "info",
  "log_format": "text",
  "log_output": "stderr",
  "log_file": "",
  "neo4j": {
    "uri": "bolt://localhost:7687",
    "username": "neo4j",
    "password": "secret",
    "database": "neo4j"
  },
  "aura": {
    "client_id": "your-client-id",
    "client_secret": "your-client-secret",
    "timeout_seconds": 30,
    "instance_defaults": {
      "tenant_id": "your-tenant-id",
      "cloud_provider": "gcp",
      "region": "europe-west1",
      "type": "enterprise-db",
      "version": "5",
      "memory": "8GB"
    }
  },
  "cypher": {
    "shell_limit": 25,
    "exec_limit": 100,
    "output_format": "table"
  },
  "telemetry": {
    "metrics": true
  }
}

Environment variables

All variables use the LOM_ prefix. Nested keys use underscores.

Variable Default Description
LOM_LOG_LEVEL info Log level: debug, info, warn, error
LOM_LOG_FORMAT text Log format: text, json
LOM_LOG_OUTPUT stderr Log destination: stderr, stdout, file
LOM_LOG_FILE (empty) Log file path (used when LOM_LOG_OUTPUT=file)
LOM_NEO4J_URI bolt://localhost:7687 Neo4j bolt URI
LOM_NEO4J_USERNAME neo4j Neo4j username
LOM_NEO4J_PASSWORD (empty) Neo4j password — prefer env over config file
LOM_NEO4J_DATABASE neo4j Neo4j database name
LOM_AURA_CLIENT_ID (empty) Aura API client ID
LOM_AURA_CLIENT_SECRET (empty) Aura API client secret — prefer env over config file
LOM_AURA_TIMEOUT_SECONDS 30 Aura API request timeout
LOM_AURA_INSTANCE_DEFAULTS_TENANT_ID (empty) Default tenant ID for new instances
LOM_AURA_INSTANCE_DEFAULTS_CLOUD_PROVIDER gcp Default cloud provider: aws, gcp, azure
LOM_AURA_INSTANCE_DEFAULTS_REGION europe-west1 Default region for new instances
LOM_AURA_INSTANCE_DEFAULTS_TYPE enterprise-db Default instance type
LOM_AURA_INSTANCE_DEFAULTS_VERSION 5 Default Neo4j version
LOM_AURA_INSTANCE_DEFAULTS_MEMORY 8GB Default instance memory
LOM_CYPHER_SHELL_LIMIT 25 Default LIMIT injected into cypher queries
LOM_CYPHER_EXEC_LIMIT 100 Default LIMIT in non-interactive mode
LOM_CYPHER_OUTPUT_FORMAT table Default output format: table, json, pretty-json, graph, toon
LOM_TELEMETRY_METRICS true Send anonymous usage metrics to Neo4j

Security note: LOM_NEO4J_PASSWORD and LOM_AURA_CLIENT_SECRET are intentionally not available as CLI flags. Passing secrets as flags exposes them in shell history and ps output.

CLI flags

--config-file string      Path to a JSON configuration file
--neo4j-uri string        Neo4j bolt URI
--neo4j-username string   Neo4j username
--neo4j-database string   Neo4j database name
--aura-client-id string   Aura API client ID
--aura-timeout int        Aura API timeout in seconds
--log-level string        Log level: debug, info, warn, error
--log-format string       Log format: text, json
--log-output string       Log destination: stderr, stdout, file
--log-file string         Log file path (when --log-output=file)
--format string           Output format: table, json, pretty-json, graph
--no-metrics              Disable anonymous usage metrics

--agent                   Enable agent mode (see Agent mode section)
--rw                      Permit write/mutating operations in agent mode
--request-id string       Correlation ID for agent-mode JSON responses
--timeout duration        Maximum command execution time (e.g. 30s)

Interactive credential prompts

When Neo4j or Aura credentials are missing, the CLI prompts for them interactively on first use and saves them to the config file. To skip prompts in automated or agent contexts, pre-populate credentials via environment variables or the config file.


Agent mode

The CLI is designed to be driven by AI agents, CI pipelines, and orchestration tools. Use --agent (or LOM_AGENT=true) to activate a safe, machine-readable operating mode.

Activating agent mode

# Via flag
lom --agent cloud instances list

# Via environment variable (recommended for pipelines — all invocations inherit it)
export LOM_AGENT=true
lom cloud instances list

What --agent does

Behaviour Human mode (default) Agent mode
Output format table json
Missing credentials Interactive prompt Structured JSON error on stdout, exit non-zero
Errors Written to stderr JSON envelope on stdout
Write operations Allowed with confirmation prompt Blocked unless --rw is also passed

The --rw flag

In agent mode, all operations that modify state are blocked by default. Pass --rw (or LOM_RW=true) to explicitly permit mutations:

# Blocked — returns READ_ONLY error
lom --agent cloud instances delete <id>

# Allowed — no prompt, executes immediately
lom --agent --rw cloud instances delete <id>

--rw governs all mutation categories uniformly:

Category Read operations Write operations (require --rw)
cypher Any read-only query Queries classified as write by Neo4j EXPLAIN
cloud instances list, get create, update, pause, resume, delete
cloud projects list, get (none currently)
admin show-users, show-databases (none currently)
config list set, delete, reset

Cypher write detection

For cypher commands in agent mode without --rw, the CLI automatically runs EXPLAIN on the query before execution. If Neo4j classifies the statement as a write (rw, w, or s), it is blocked:

# EXPLAIN detects a write — blocked
lom --agent cypher "CREATE (n:Person {name:'Alice'}) RETURN n"
# → {"status":"error","error":{"code":"WRITE_BLOCKED","message":"..."},...}

# Read query — EXPLAIN confirms safe, executes
lom --agent cypher "MATCH (n:Person) RETURN n.name LIMIT 10"

# EXPLAIN or PROFILE queries run as-is — no pre-check
lom --agent cypher "EXPLAIN MATCH (n) RETURN n"

With --rw, the EXPLAIN pre-check is skipped and queries execute directly.

Error envelope

All errors in agent mode are written to stdout as a JSON envelope so agents reading stdout get machine-readable failures:

{"status":"error","error":{"code":"READ_ONLY","message":"\"delete\" is a write operation; re-run with --rw to permit mutations"},"request_id":"a1b2c3","schema_version":"1"}

Error codes:

Code Meaning
READ_ONLY Write operation attempted without --rw
WRITE_BLOCKED Cypher write detected by EXPLAIN without --rw
MISSING_QUERY No cypher statement provided in agent mode
MISSING_CREDENTIALS Required credentials absent (no prompt in agent mode)
TIMEOUT Command exceeded --timeout duration
EXECUTION_ERROR Any other failure

Additional agent flags

--request-id string   Correlation ID included in JSON responses.
                      Auto-generated (UUID) if not supplied.
                      Env: LOM_REQUEST_ID

--timeout duration    Maximum time for a command to run (e.g. 30s, 2m).
                      Exit code 1 + TIMEOUT error on expiry.

Recommended orchestrator setup

export LOM_AGENT=true
export LOM_REQUEST_ID="pipeline-run-${RUN_ID}"  # inject your trace ID
export LOM_NEO4J_URI="bolt+s://your-instance.databases.neo4j.io"
export LOM_NEO4J_USERNAME="neo4j"
export LOM_NEO4J_PASSWORD="${NEO4J_PASSWORD}"

# Read operations work with no further flags
lom cypher "MATCH (n:Person) RETURN count(n)"

# Write operations require explicit --rw
lom --rw cypher "CREATE (n:Event {ts: datetime()}) RETURN n"

Contributing

Project structure

cmd/lom/
    main.go             Entry point — calls run() and os.Exit
    app.go              App struct, Cobra root command, startup wiring, flag definitions,
                        subcommand builders (buildCloudCommand, buildCypherCommand, etc.)

internal/
    config/             Config structs, Viper loader, Overrides, SaveConfiguration
    logger/             Logger interface and slog implementation
    analytics/          Mixpanel analytics service
    presentation/       Output formatters (text, JSON, pretty-JSON, table, graph)
    repository/         GraphRepository interface and Neo4j driver implementation
    service/
        interfaces.go       CypherService, CloudService, AdminService interfaces
        cypher_service.go
        cloud_service.go
        admin_service.go
        graph_service.go
    commands/           Category builders (pure wiring — no business logic)
        cypher.go
        cloud.go
        admin.go
        config.go           config list/set/delete/reset category
        prerequisites.go    Neo4jPrerequisite, AuraPrerequisite, interactive variants
    dispatch/           Command routing primitives
        dispatch.go         Registry interface, CommandHandler type, Context struct
        category.go         Category and Command types — Dispatch, Find, SetPrerequisite
    tool/               Tool interface, BaseTool, Context, Result, IOHandler
    tools/              Concrete tool implementations (echo, help, query) + ToolRegistry

The dependency direction is strict:

cmd  →  commands  →  service  →  repository
cmd  →  dispatch
cmd  →  tools
commands  →  dispatch   (for Category / Command / Context types)

No package imports its own parent. dispatch does not import commands or service.


Adding a tool

Tools are flat, named executables registered in the tool registry.

Step 1 — Create the file

Create internal/tools/mytool.go. Embed *tool.BaseTool to get parameter helpers for free:

package tools

import (
    "fmt"
    "github.com/cli/go-cli-tool/internal/tool"
)

type MyTool struct {
    *tool.BaseTool
    prefix string
}

func NewMyTool() *MyTool {
    return &MyTool{
        BaseTool: tool.NewBaseTool(
            "mytool",                        // name — must be unique in the registry
            "Does something interesting",    // description shown in help
            "1.0.0",
        ),
        prefix: ">>",
    }
}

Step 2 — Implement the interface

BaseTool provides no-op defaults for Validate and Configure. Override only the ones you need:

func (t *MyTool) Execute(ctx tool.Context) (tool.Result, error) {
    if len(ctx.Args) == 0 {
        return tool.ErrorResult("usage: mytool <text>"), fmt.Errorf("no input")
    }
    output := fmt.Sprintf("%s %s", t.prefix, ctx.Args[0])
    return tool.SuccessResult(output), nil
}

func (t *MyTool) Validate(ctx tool.Context) error {
    if len(ctx.Args) == 0 {
        return fmt.Errorf("at least one argument is required")
    }
    return nil
}

func (t *MyTool) Configure(params map[string]interface{}) error {
    t.BaseTool.Configure(params) // always call through first
    if v, ok := params["prefix"].(string); ok {
        t.prefix = v
    }
    return nil
}

func (t *MyTool) DefaultParams() map[string]interface{} {
    return map[string]interface{}{"prefix": ">>"}
}

Step 3 — Register it

In cmd/lom/app.go, add your tool to the slice inside buildRegistry:

for _, t := range []tool.Tool{
    tools.NewEchoTool(),
    tools.NewHelpTool(registry),
    tools.NewQueryTool(cypherSvc),
    tools.NewMyTool(),           // ← add here
} {
    registerTool(registry, t, cfg, log)
}

Step 4 — (Optional) Configure via config file

{
  "tools": {
    "mytool": {
      "enabled": true,
      "params": {
        "prefix": "---"
      }
    }
  }
}

Adding a command

A command sits inside an existing category or sub-category. It takes positional arguments and returns a formatted string.

Example: adding admin show-indexes to the admin category

Open internal/commands/admin.go and chain another AddCommand call:

func BuildAdminCategory(svc service.AdminService) *dispatch.Category {
    return dispatch.NewCategory("admin", "Administrative operations...").
        AddCommand(&dispatch.Command{
            Name:        "show-users",
            // ... existing command ...
        }).
        AddCommand(&dispatch.Command{
            Name:        "show-indexes",
            Aliases:     []string{"idx"},
            Usage:       "show-indexes",
            Description: "List all indexes in the current database",
            Handler: func(args []string, ctx dispatch.Context) (string, error) {
                return svc.ShowIndexes(ctx.Context)
            },
        })
}

Aliases are registered automatically in dispatch and appear in parentheses in --help output:

lom admin show-indexes
lom admin idx           # same command

Example: adding a command to a sub-category

To add cloud instances clone <id>, open internal/commands/cloud.go and chain another AddCommand in buildInstancesCategory:

func buildInstancesCategory(svc service.CloudService) *dispatch.Category {
    return dispatch.NewCategory("instances", "Manage Aura DB instances").
        AddCommand(instanceListCmd(svc)).
        // ...existing commands...
        AddCommand(&dispatch.Command{
            Name:        "clone",
            Usage:       "clone <id>",
            Description: "Clone an existing instance",
            Handler: func(args []string, ctx dispatch.Context) (string, error) {
                if len(args) == 0 {
                    return "", fmt.Errorf("usage: cloud instances clone <id>")
                }
                return fmt.Sprintf("Instance %s cloned.", args[0]), nil
            },
        })
}

Adding a category

To add a new top-level category (e.g. gds for Graph Data Science):

Step 1 — Add a service interface

In internal/service/interfaces.go:

type GDSService interface {
    ListAlgorithms(ctx context.Context) ([]string, error)
    RunPageRank(ctx context.Context, graphName string) (string, error)
}

Step 2 — Implement the service

Create internal/service/gds_service.go:

package service

type GDSServiceImpl struct {
    repo repository.GraphRepository
}

func NewGDSService(repo repository.GraphRepository) GDSService {
    return &GDSServiceImpl{repo: repo}
}

func (s *GDSServiceImpl) ListAlgorithms(ctx context.Context) ([]string, error) {
    // CALL gds.list()
    return nil, nil
}

Step 3 — Build the category

Create internal/commands/gds.go:

package commands

import (
    "strings"

    "github.com/cli/go-cli-tool/internal/dispatch"
    "github.com/cli/go-cli-tool/internal/service"
)

func BuildGDSCategory(svc service.GDSService) *dispatch.Category {
    return dispatch.NewCategory("gds", "Graph Data Science operations").
        AddCommand(&dispatch.Command{
            Name:        "list-algorithms",
            Usage:       "list-algorithms",
            Description: "List available GDS algorithms",
            Handler: func(args []string, ctx dispatch.Context) (string, error) {
                algos, err := svc.ListAlgorithms(ctx.Context)
                if err != nil {
                    return "", err
                }
                return strings.Join(algos, "\n"), nil
            },
        })
}

Step 4 — Wire it into App

In cmd/lom/app.go, add the service field, construct it in newApp, and register the category and its Cobra subcommand:

// In newApp(), after repo is created:
gdsSvc := service.NewGDSService(repo)

// In buildCategories():
"gds": commands.BuildGDSCategory(a.gdsSvc).
    SetPrerequisite(commands.InteractiveNeo4jPrerequisite(&a.cfg.Neo4j, a.cfg, configPath)),

// In buildRootCommand():
rootCmd.AddCommand(buildGDSCommand())

func buildGDSCommand() *cobra.Command {
    return &cobra.Command{
        Use:   "gds",
        Short: "Graph Data Science operations",
        RunE:  runCategory("gds"),
        SilenceUsage:  true,
        SilenceErrors: true,
    }
}

Use InteractiveNeo4jPrerequisite for database-connected categories and InteractiveAuraPrerequisite for Aura API categories. Add new prerequisite factories to internal/commands/prerequisites.go if neither fits.

The category is then available as a direct subcommand:

lom gds list-algorithms
lom gds --help

Code conventions

Service pattern — business logic lives in internal/service. Command handlers in internal/commands call services; they contain no logic of their own beyond argument validation and output formatting.

Interfaces before implementations — new behaviour starts with an interface in internal/service/interfaces.go. This keeps the command layer decoupled from concrete implementations and makes testing straightforward.

Prerequisite checks belong in prerequisites.go — if a category requires an external dependency (database connection, API credentials), declare it with SetPrerequisite in buildCategories. Write the factory function in internal/commands/prerequisites.go so it is independently testable. The check runs before every real dispatch, but bare category invocations (e.g. lom cypher --help) always show help regardless.

Tool Validate runs before ExecuteValidate is called automatically before every Execute. Use it for tool-level readiness checks rather than repeating them inside Execute. BaseTool.Validate is a no-op; only override it when needed.

Command aliases are first-class — add short-form names via the Aliases []string field on dispatch.Command. Aliases are resolved in dispatch and shown in --help output. Register the canonical name as Name; aliases are supplementary.

Secrets stay out of flags — passwords and API secrets must not be CLI flags. Accept them only via environment variables, the config file, or interactive prompts.

Errors are the caller's responsibility — return fmt.Errorf("context: %w", err) and let the caller handle it. Don't call os.Exit or log.Fatal from inside a service or command handler.

No imports up the stackdispatch does not import commands or service. commands does not import tools. Keep the dependency graph acyclic and flowing in one direction toward cmd.

Declare MutationMode on every command and tool — every dispatch.Command and tool.Tool must declare its MutationMode. Use ModeRead (default) for read-only operations, ModeWrite for operations that always modify state, and ModeConditional for operations where mutability depends on runtime input (Cypher queries). The dispatcher enforces the read-only contract in agent mode automatically, so individual handlers do not need to check ctx.AgentMode for blocking. Handlers should check ctx.AgentMode only to suppress interactive prompts (e.g. confirmation dialogs).


CI & Releases

One GitHub Actions workflow manages the release process.

Workflows

Workflow Trigger What it does
Release Push of a vX.Y.Z tag Gates on tests, builds cross-platform binaries via GoReleaser, extracts the changelog section, creates a GitHub Release

Making a release

Releases follow a four-step process. changie collects unreleased fragment files and determines the correct semver bump automatically from the change kinds (Added → minor, Fixed/Security → patch, Changed/Removed → major).

1. Batch and merge the changelog

changie batch   # collects .changes/unreleased/*.yaml → .changes/vX.Y.Z.md
changie merge   # folds that file into CHANGELOG.md

2. Commit and tag

git add CHANGELOG.md .changes/
git commit -m "chore: release v0.2.0"
git tag v0.2.0
git push origin main --tags

Adding a changelog entry

Every PR that changes Go source files needs a changie fragment. Run:

changie new

Choose a kind and write a one-line summary, then commit the generated .yaml file alongside your code changes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

lom-3.2.1-py3-none-win_arm64.whl (19.4 MB view details)

Uploaded Python 3Windows ARM64

lom-3.2.1-py3-none-win_amd64.whl (20.7 MB view details)

Uploaded Python 3Windows x86-64

lom-3.2.1-py3-none-manylinux_2_17_x86_64.whl (20.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

lom-3.2.1-py3-none-manylinux_2_17_aarch64.whl (19.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

lom-3.2.1-py3-none-macosx_11_0_arm64.whl (19.5 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

lom-3.2.1-py3-none-macosx_10_9_x86_64.whl (20.4 MB view details)

Uploaded Python 3macOS 10.9+ x86-64

File details

Details for the file lom-3.2.1-py3-none-win_arm64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-win_arm64.whl
  • Upload date:
  • Size: 19.4 MB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 72a447ef7bbaa5772c0495c073417eabee98281928e8246068ad77af5ca35b64
MD5 5af8c70add57b7c040acac047bc727d7
BLAKE2b-256 e63df9db5b41279ef1fce174aec8dc5e1ebb894965120bc0a58ce8245a8344df

See more details on using hashes here.

File details

Details for the file lom-3.2.1-py3-none-win_amd64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-win_amd64.whl
  • Upload date:
  • Size: 20.7 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ff5209133e7eef95ccac2477d5fc90b2d57f1e6d3d2e5b1633ee63c7c0892b60
MD5 fa1282418ea760d7158b4c129621149c
BLAKE2b-256 972e85c214b16012f0536f0824b17f3c66b2ccbfc9124ef108443ed7e531fb92

See more details on using hashes here.

File details

Details for the file lom-3.2.1-py3-none-manylinux_2_17_x86_64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-manylinux_2_17_x86_64.whl
  • Upload date:
  • Size: 20.2 MB
  • Tags: Python 3, manylinux: glibc 2.17+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 17eb57fe5e0a74042ad209c8f456a9ca6140e63e63d9c38fc9f387b47d495d29
MD5 37ef962842b91abf5cda4f90f6274fb8
BLAKE2b-256 06da385b85d6564ce85646b1e45474cb510ed0089566b3162cfb320bbcc24ed4

See more details on using hashes here.

File details

Details for the file lom-3.2.1-py3-none-manylinux_2_17_aarch64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-manylinux_2_17_aarch64.whl
  • Upload date:
  • Size: 19.2 MB
  • Tags: Python 3, manylinux: glibc 2.17+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 394c7a6c4674921e9ada11611828471c4b3f39598403a33dda656cbb8103018b
MD5 63f786b76ce1b01758f0beaf218076af
BLAKE2b-256 088d4282a98498693255851ac6791d60d0fb9683798ff63fa8e665e2b74ad1b7

See more details on using hashes here.

File details

Details for the file lom-3.2.1-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 19.5 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 b16609ee5a7ea32ca01cb38aad16c4b57cb4049ff5eded3be341cc0e37845136
MD5 fdfac95f87d1847922a9495bfc376a77
BLAKE2b-256 cf81a1a4df91f950ab534184a24a878c84130b4a0c33c1801b6dd829f0a7453f

See more details on using hashes here.

File details

Details for the file lom-3.2.1-py3-none-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: lom-3.2.1-py3-none-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 20.4 MB
  • Tags: Python 3, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for lom-3.2.1-py3-none-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 1856d395dc19b84fcb6223dd697522f98ff319806fd5b298e3b534bdd074fcab
MD5 847008cab293e4ff7c0d8a05e790fd98
BLAKE2b-256 e1b4ce360206e28fc1dd43fae8ef99824b003ff150263ddfd90ead8567cf8837

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page