basic-memory 0.2.20__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basic-memory might be problematic. Click here for more details.

basic_memory/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  """basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
2
2
 
3
- __version__ = "0.0.1"
3
+ __version__ = "0.3.0"
basic_memory/api/app.py CHANGED
@@ -6,38 +6,17 @@ from fastapi import FastAPI, HTTPException
6
6
  from fastapi.exception_handlers import http_exception_handler
7
7
  from loguru import logger
8
8
 
9
+ import basic_memory
9
10
  from basic_memory import db
10
11
  from basic_memory.config import config as app_config
11
12
  from basic_memory.api.routers import knowledge, search, memory, resource
12
- from alembic import command
13
- from alembic.config import Config
14
-
15
- from basic_memory.db import DatabaseType
16
- from basic_memory.repository.search_repository import SearchRepository
17
-
18
-
19
- async def run_migrations(): # pragma: no cover
20
- """Run any pending alembic migrations."""
21
- logger.info("Running database migrations...")
22
- try:
23
- config = Config("alembic.ini")
24
- command.upgrade(config, "head")
25
- logger.info("Migrations completed successfully")
26
-
27
- _, session_maker = await db.get_or_create_db(
28
- app_config.database_path, DatabaseType.FILESYSTEM
29
- )
30
- await SearchRepository(session_maker).init_search_index()
31
- except Exception as e:
32
- logger.error(f"Error running migrations: {e}")
33
- raise
34
13
 
35
14
 
36
15
  @asynccontextmanager
37
16
  async def lifespan(app: FastAPI): # pragma: no cover
38
17
  """Lifecycle manager for the FastAPI app."""
39
- logger.info("Starting Basic Memory API")
40
- await run_migrations()
18
+ logger.info(f"Starting Basic Memory API {basic_memory.__version__}")
19
+ await db.run_migrations(app_config)
41
20
  yield
42
21
  logger.info("Shutting down Basic Memory API")
43
22
  await db.shutdown_db()
basic_memory/cli/app.py CHANGED
@@ -1,3 +1,13 @@
1
+ import asyncio
2
+
1
3
  import typer
2
4
 
5
+ from basic_memory import db
6
+ from basic_memory.config import config
7
+ from basic_memory.utils import setup_logging
8
+
9
+ setup_logging(log_file=".basic-memory/basic-memory-cli.log") # pragma: no cover
10
+
11
+ asyncio.run(db.run_migrations(config))
12
+
3
13
  app = typer.Typer()
@@ -22,4 +22,4 @@ def reset(
22
22
  from basic_memory.cli.commands.sync import sync
23
23
 
24
24
  logger.info("Rebuilding search index from filesystem...")
25
- asyncio.run(sync()) # pyright: ignore
25
+ sync(watch=False) # pyright: ignore
@@ -12,9 +12,9 @@ import basic_memory.mcp.tools # noqa: F401 # pragma: no cover
12
12
 
13
13
 
14
14
  @app.command()
15
- def mcp():
15
+ def mcp(): # pragma: no cover
16
16
  """Run the MCP server for Claude Desktop integration."""
17
17
  home_dir = config.home
18
- logger.info("Starting Basic Memory MCP server")
18
+ logger.info(f"Starting Basic Memory MCP server {basic_memory.__version__}")
19
19
  logger.info(f"Home directory: {home_dir}")
20
20
  mcp_server.run()
@@ -25,13 +25,11 @@ async def get_file_change_scanner(
25
25
  db_type=DatabaseType.FILESYSTEM,
26
26
  ) -> FileChangeScanner: # pragma: no cover
27
27
  """Get sync service instance."""
28
- async with db.engine_session_factory(db_path=config.database_path, db_type=db_type) as (
29
- engine,
30
- session_maker,
31
- ):
32
- entity_repository = EntityRepository(session_maker)
33
- file_change_scanner = FileChangeScanner(entity_repository)
34
- return file_change_scanner
28
+ _, session_maker = await db.get_or_create_db(db_path=config.database_path, db_type=db_type)
29
+
30
+ entity_repository = EntityRepository(session_maker)
31
+ file_change_scanner = FileChangeScanner(entity_repository)
32
+ return file_change_scanner
35
33
 
36
34
 
37
35
  def add_files_to_tree(
@@ -14,7 +14,6 @@ from rich.tree import Tree
14
14
  from basic_memory import db
15
15
  from basic_memory.cli.app import app
16
16
  from basic_memory.config import config
17
- from basic_memory.db import DatabaseType
18
17
  from basic_memory.markdown import EntityParser
19
18
  from basic_memory.markdown.markdown_processor import MarkdownProcessor
20
19
  from basic_memory.repository import (
@@ -39,50 +38,50 @@ class ValidationIssue:
39
38
  error: str
40
39
 
41
40
 
42
- async def get_sync_service(db_type=DatabaseType.FILESYSTEM): # pragma: no cover
41
+ async def get_sync_service(): # pragma: no cover
43
42
  """Get sync service instance with all dependencies."""
44
- async with db.engine_session_factory(db_path=config.database_path, db_type=db_type) as (
45
- engine,
46
- session_maker,
47
- ):
48
- entity_parser = EntityParser(config.home)
49
- markdown_processor = MarkdownProcessor(entity_parser)
50
- file_service = FileService(config.home, markdown_processor)
51
-
52
- # Initialize repositories
53
- entity_repository = EntityRepository(session_maker)
54
- observation_repository = ObservationRepository(session_maker)
55
- relation_repository = RelationRepository(session_maker)
56
- search_repository = SearchRepository(session_maker)
57
-
58
- # Initialize services
59
- search_service = SearchService(search_repository, entity_repository, file_service)
60
- link_resolver = LinkResolver(entity_repository, search_service)
61
-
62
- # Initialize scanner
63
- file_change_scanner = FileChangeScanner(entity_repository)
64
-
65
- # Initialize services
66
- entity_service = EntityService(
67
- entity_parser,
68
- entity_repository,
69
- observation_repository,
70
- relation_repository,
71
- file_service,
72
- link_resolver,
73
- )
74
-
75
- # Create sync service
76
- sync_service = SyncService(
77
- scanner=file_change_scanner,
78
- entity_service=entity_service,
79
- entity_parser=entity_parser,
80
- entity_repository=entity_repository,
81
- relation_repository=relation_repository,
82
- search_service=search_service,
83
- )
84
-
85
- return sync_service
43
+ _, session_maker = await db.get_or_create_db(
44
+ db_path=config.database_path, db_type=db.DatabaseType.FILESYSTEM
45
+ )
46
+
47
+ entity_parser = EntityParser(config.home)
48
+ markdown_processor = MarkdownProcessor(entity_parser)
49
+ file_service = FileService(config.home, markdown_processor)
50
+
51
+ # Initialize repositories
52
+ entity_repository = EntityRepository(session_maker)
53
+ observation_repository = ObservationRepository(session_maker)
54
+ relation_repository = RelationRepository(session_maker)
55
+ search_repository = SearchRepository(session_maker)
56
+
57
+ # Initialize services
58
+ search_service = SearchService(search_repository, entity_repository, file_service)
59
+ link_resolver = LinkResolver(entity_repository, search_service)
60
+
61
+ # Initialize scanner
62
+ file_change_scanner = FileChangeScanner(entity_repository)
63
+
64
+ # Initialize services
65
+ entity_service = EntityService(
66
+ entity_parser,
67
+ entity_repository,
68
+ observation_repository,
69
+ relation_repository,
70
+ file_service,
71
+ link_resolver,
72
+ )
73
+
74
+ # Create sync service
75
+ sync_service = SyncService(
76
+ scanner=file_change_scanner,
77
+ entity_service=entity_service,
78
+ entity_parser=entity_parser,
79
+ entity_repository=entity_repository,
80
+ relation_repository=relation_repository,
81
+ search_service=search_service,
82
+ )
83
+
84
+ return sync_service
86
85
 
87
86
 
88
87
  def group_issues_by_directory(issues: List[ValidationIssue]) -> Dict[str, List[ValidationIssue]]:
@@ -154,6 +153,7 @@ def display_detailed_sync_results(knowledge: SyncReport):
154
153
 
155
154
  async def run_sync(verbose: bool = False, watch: bool = False):
156
155
  """Run sync operation."""
156
+
157
157
  sync_service = await get_sync_service()
158
158
 
159
159
  # Start watching if requested
basic_memory/db.py CHANGED
@@ -4,6 +4,10 @@ from enum import Enum, auto
4
4
  from pathlib import Path
5
5
  from typing import AsyncGenerator, Optional
6
6
 
7
+ from basic_memory.config import ProjectConfig
8
+ from alembic import command
9
+ from alembic.config import Config
10
+
7
11
  from loguru import logger
8
12
  from sqlalchemy import text
9
13
  from sqlalchemy.ext.asyncio import (
@@ -14,8 +18,7 @@ from sqlalchemy.ext.asyncio import (
14
18
  async_scoped_session,
15
19
  )
16
20
 
17
- from basic_memory.models import Base
18
- from basic_memory.models.search import CREATE_SEARCH_INDEX
21
+ from basic_memory.repository.search_repository import SearchRepository
19
22
 
20
23
  # Module level state
21
24
  _engine: Optional[AsyncEngine] = None
@@ -35,7 +38,7 @@ class DatabaseType(Enum):
35
38
  logger.info("Using in-memory SQLite database")
36
39
  return "sqlite+aiosqlite://"
37
40
 
38
- return f"sqlite+aiosqlite:///{db_path}"
41
+ return f"sqlite+aiosqlite:///{db_path}" # pragma: no cover
39
42
 
40
43
 
41
44
  def get_scoped_session_factory(
@@ -69,24 +72,6 @@ async def scoped_session(
69
72
  await factory.remove()
70
73
 
71
74
 
72
- async def init_db() -> None:
73
- """Initialize database with required tables."""
74
- if _session_maker is None: # pragma: no cover
75
- raise RuntimeError("Database session maker not initialized")
76
-
77
- logger.info("Initializing database...")
78
-
79
- async with scoped_session(_session_maker) as session:
80
- await session.execute(text("PRAGMA foreign_keys=ON"))
81
- conn = await session.connection()
82
- await conn.run_sync(Base.metadata.create_all)
83
-
84
- # recreate search index
85
- await session.execute(CREATE_SEARCH_INDEX)
86
-
87
- await session.commit()
88
-
89
-
90
75
  async def get_or_create_db(
91
76
  db_path: Path,
92
77
  db_type: DatabaseType = DatabaseType.FILESYSTEM,
@@ -100,9 +85,6 @@ async def get_or_create_db(
100
85
  _engine = create_async_engine(db_url, connect_args={"check_same_thread": False})
101
86
  _session_maker = async_sessionmaker(_engine, expire_on_commit=False)
102
87
 
103
- # Initialize database
104
- await init_db()
105
-
106
88
  assert _engine is not None # for type checker
107
89
  assert _session_maker is not None # for type checker
108
90
  return _engine, _session_maker
@@ -122,7 +104,6 @@ async def shutdown_db() -> None: # pragma: no cover
122
104
  async def engine_session_factory(
123
105
  db_path: Path,
124
106
  db_type: DatabaseType = DatabaseType.MEMORY,
125
- init: bool = True,
126
107
  ) -> AsyncGenerator[tuple[AsyncEngine, async_sessionmaker[AsyncSession]], None]:
127
108
  """Create engine and session factory.
128
109
 
@@ -139,9 +120,6 @@ async def engine_session_factory(
139
120
  try:
140
121
  _session_maker = async_sessionmaker(_engine, expire_on_commit=False)
141
122
 
142
- if init:
143
- await init_db()
144
-
145
123
  assert _engine is not None # for type checker
146
124
  assert _session_maker is not None # for type checker
147
125
  yield _engine, _session_maker
@@ -150,3 +128,18 @@ async def engine_session_factory(
150
128
  await _engine.dispose()
151
129
  _engine = None
152
130
  _session_maker = None
131
+
132
+
133
+ async def run_migrations(app_config: ProjectConfig, database_type=DatabaseType.FILESYSTEM):
134
+ """Run any pending alembic migrations."""
135
+ logger.info("Running database migrations...")
136
+ try:
137
+ config = Config("alembic.ini")
138
+ command.upgrade(config, "head")
139
+ logger.info("Migrations completed successfully")
140
+
141
+ _, session_maker = await get_or_create_db(app_config.database_path, database_type)
142
+ await SearchRepository(session_maker).init_search_index()
143
+ except Exception as e: # pragma: no cover
144
+ logger.error(f"Error running migrations: {e}")
145
+ raise
@@ -2,7 +2,7 @@ from httpx import ASGITransport, AsyncClient
2
2
 
3
3
  from basic_memory.api.app import app as fastapi_app
4
4
 
5
- BASE_URL = "http://test"
5
+ BASE_URL = "memory://"
6
6
 
7
7
  # Create shared async client
8
8
  client = AsyncClient(transport=ASGITransport(app=fastapi_app), base_url=BASE_URL)
@@ -13,6 +13,7 @@ from basic_memory.mcp.async_client import client
13
13
  from basic_memory.schemas import EntityResponse, DeleteEntitiesResponse
14
14
  from basic_memory.schemas.base import Entity
15
15
  from basic_memory.mcp.tools.utils import call_get, call_put, call_delete
16
+ from basic_memory.schemas.memory import memory_url_path
16
17
 
17
18
 
18
19
  @mcp.tool(
@@ -96,7 +97,9 @@ async def read_note(identifier: str) -> str:
96
97
  Raises:
97
98
  ValueError: If the note cannot be found
98
99
  """
99
- response = await call_get(client, f"/resource/{identifier}")
100
+ logger.info(f"Reading note {identifier}")
101
+ url = memory_url_path(identifier)
102
+ response = await call_get(client, f"/resource/{url}")
100
103
  return response.text
101
104
 
102
105
 
@@ -1,10 +1,7 @@
1
1
  """Types and utilities for file sync."""
2
2
 
3
3
  from dataclasses import dataclass, field
4
- from typing import Set, Dict, Optional
5
-
6
- from watchfiles import Change
7
-
4
+ from typing import Set, Dict
8
5
 
9
6
 
10
7
  @dataclass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basic-memory
3
- Version: 0.2.20
3
+ Version: 0.3.0
4
4
  Summary: Local-first knowledge management combining Zettelkasten with knowledge graphs
5
5
  Project-URL: Homepage, https://github.com/basicmachines-co/basic-memory
6
6
  Project-URL: Repository, https://github.com/basicmachines-co/basic-memory
@@ -1,6 +1,6 @@
1
- basic_memory/__init__.py,sha256=_ij75bUYM3LqRQYHrJ1kLnDuUyauuHilEBF96OFw9hA,122
1
+ basic_memory/__init__.py,sha256=-7V4k4cOLWxlII4cUrwXI3O7dNeKe4KfomyyMZla3ws,122
2
2
  basic_memory/config.py,sha256=PZA2qgwKACvKfRcM3H-BPB_8FYVhgZAwTmlKJ3ROfhU,1643
3
- basic_memory/db.py,sha256=BFZCp4aJ7Xj9_ZCMz0rnSBuCy5xIMvvWjSImmuKzdWg,4605
3
+ basic_memory/db.py,sha256=cN8g_5dTMjQZKCvy_NwWs3dXV5lZZL7DCeu99guIK5k,4613
4
4
  basic_memory/deps.py,sha256=UzivBw6e6iYcU_8SQ8LNCmSsmFyHfjdzfWvnfNzqbRc,5375
5
5
  basic_memory/file_utils.py,sha256=gp7RCFWaddFnELIyTc1E19Rk8jJsrKshG2n8ZZR-kKA,5751
6
6
  basic_memory/utils.py,sha256=HiLorP5_YCQeNeTcDqvnkrwY7OBaFRS3i_hdV9iWKLs,2374
@@ -10,21 +10,21 @@ basic_memory/alembic/migrations.py,sha256=CIbkMHEKZ60aDUhFGSQjv8kDNM7sazfvEYHGGc
10
10
  basic_memory/alembic/script.py.mako,sha256=MEqL-2qATlST9TAOeYgscMn1uy6HUS9NFvDgl93dMj8,635
11
11
  basic_memory/alembic/versions/3dae7c7b1564_initial_schema.py,sha256=lTbWlAnd1es7xU99DoJgfaRe1_Kte8TL98riqeKGV80,4363
12
12
  basic_memory/api/__init__.py,sha256=wCpj-21j1D0KzKl9Ql6unLBVFY0K1uGp_FeSZRKtqpk,72
13
- basic_memory/api/app.py,sha256=AEHcslN4SBq5Ni7q7wkG4jDH0-SwMWV2DeTdaUSQKns,2083
13
+ basic_memory/api/app.py,sha256=3ddcWTxVjMy_5SUq89kROhMwosZqcr67Q5evOlSR9GE,1389
14
14
  basic_memory/api/routers/__init__.py,sha256=iviQ1QVYobC8huUuyRhEjcA0BDjrOUm1lXHXhJkxP9A,239
15
15
  basic_memory/api/routers/knowledge_router.py,sha256=cMLhRczOfSRnsZdyR0bSS8PENPRTu70dlwaV27O34bs,5705
16
16
  basic_memory/api/routers/memory_router.py,sha256=pF0GzmWoxmjhtxZM8jCmfLwqjey_fmXER5vYbD8fsQw,4556
17
17
  basic_memory/api/routers/resource_router.py,sha256=_Gp5HSJr-L-GUkQKbEP2bAZvCY8Smd-sBNWpGyqXS4c,1056
18
18
  basic_memory/api/routers/search_router.py,sha256=dCRnBbp3r966U8UYwgAaxZBbg7yX7pC8QJqagdACUi0,1086
19
19
  basic_memory/cli/__init__.py,sha256=arcKLAWRDhPD7x5t80MlviZeYzwHZ0GZigyy3NKVoGk,33
20
- basic_memory/cli/app.py,sha256=hF4MgYCgFql4J6qi3lguqc6HQdP2gm6PpvtSxKBSjZc,34
20
+ basic_memory/cli/app.py,sha256=y7wU5kOPPpfnRc_J018tE_5dj23S2c4KVa9T-7ak1Ss,285
21
21
  basic_memory/cli/main.py,sha256=Vvpmh33MSZJftCENEjzJH3yBbxD4B40Pl6IBIumiVX4,505
22
22
  basic_memory/cli/commands/__init__.py,sha256=OQGLaKTsOdPsp2INM_pHzmOlbVfdL0sytBNgvqTqCDY,159
23
- basic_memory/cli/commands/db.py,sha256=I92CRufPskvHl9c90f5Eg7U7D0uIzLBiwngQuAh5cLk,772
23
+ basic_memory/cli/commands/db.py,sha256=XW2ujzas5j2Gf01NOPQI89L4NK-21GksO_OIekKxv6c,770
24
24
  basic_memory/cli/commands/import_memory_json.py,sha256=ZXSRHH_3GgJzmMLvDulakKIpzsKxrZIUmEuWgJmwMOE,5138
25
- basic_memory/cli/commands/mcp.py,sha256=a0v54iFL01_eykODHuWIupTHCn-COm-WZGdSO5iinc0,563
26
- basic_memory/cli/commands/status.py,sha256=aNpP8u-ECoVTiL5MIb-D2cXXLJtv6z2z8CMCh5nt2KY,5782
27
- basic_memory/cli/commands/sync.py,sha256=sb6OGl9IVZLmGfHUm0-aexD365BRTaHJhpwqt0O5yxk,7035
25
+ basic_memory/cli/commands/mcp.py,sha256=BPdThcufdriIvrDskc87a0oCC1BkZ0PZsgNao_-oNKk,611
26
+ basic_memory/cli/commands/status.py,sha256=G7aAdbCuiFe38VFxMTcAfY2DKqol3WIQxYa491ui4yM,5728
27
+ basic_memory/cli/commands/sync.py,sha256=LpoEPstcguhRPT2bwsbAI3ypiY0cDoNn_gxUmLpX21Q,6827
28
28
  basic_memory/markdown/__init__.py,sha256=DdzioCWtDnKaq05BHYLgL_78FawEHLpLXnp-kPSVfIc,501
29
29
  basic_memory/markdown/entity_parser.py,sha256=sJk8TRUd9cAaIjATiJn7dBQRorrYngRbd7MRVfc0Oc4,3781
30
30
  basic_memory/markdown/markdown_processor.py,sha256=mV3pYoDTaQMEl1tA5n_XztBvNlYyH2SzKs4vnKdAet4,4952
@@ -32,12 +32,12 @@ basic_memory/markdown/plugins.py,sha256=gtIzKRjoZsyvBqLpVNnrmzl_cbTZ5ZGn8kcuXxQj
32
32
  basic_memory/markdown/schemas.py,sha256=mzVEDUhH98kwETMknjkKw5H697vg_zUapsJkJVi17ho,1894
33
33
  basic_memory/markdown/utils.py,sha256=ZtHa-dG--ZwFEUC3jfl04KZGhM_ZWo5b-8d8KpJ90gY,2758
34
34
  basic_memory/mcp/__init__.py,sha256=dsDOhKqjYeIbCULbHIxfcItTbqudEuEg1Np86eq0GEQ,35
35
- basic_memory/mcp/async_client.py,sha256=Eo345wANiBRSM4u3j_Vd6Ax4YtMg7qbWd9PIoFfj61I,236
35
+ basic_memory/mcp/async_client.py,sha256=vMN5nApPA428Oz4Siq2mNTiBjTcM5A5OSZTnX7_sDxE,234
36
36
  basic_memory/mcp/server.py,sha256=L92Vit7llaKT9NlPZfxdp67C33niObmRH2QFyUhmnD0,355
37
37
  basic_memory/mcp/tools/__init__.py,sha256=MHZmWw016N0qbtC3f186Jg1tPzh2g88_ZsCKJ0oyrrs,873
38
38
  basic_memory/mcp/tools/knowledge.py,sha256=2U8YUKCizsAETHCC1mBVKMfCEef6tlc_pa2wOmA9mD4,2016
39
39
  basic_memory/mcp/tools/memory.py,sha256=gl4MBm9l2lMOfu_xmUqjoZacWSIHOAYZiAm8z7oDuY8,5203
40
- basic_memory/mcp/tools/notes.py,sha256=4GKnhDK53UkeZtpZENQ9id9XdemKxLzGwMQJeuX-Kok,3772
40
+ basic_memory/mcp/tools/notes.py,sha256=pe7n0f0_nrkjnq6E4PCr7L8oOvzMnQgthfJNy9Vr3DE,3905
41
41
  basic_memory/mcp/tools/search.py,sha256=tx6aIuB2FWmmrvzu3RHSQvszlk-zHcwrWhkLLHWjuZc,1105
42
42
  basic_memory/mcp/tools/utils.py,sha256=icm-Xyqw3GxooGYkXqjEjoZvIGy_Z3CPw-uUYBxR_YQ,4831
43
43
  basic_memory/models/__init__.py,sha256=Bf0xXV_ryndogvZDiVM_Wb6iV2fHUxYNGMZNWNcZi0s,307
@@ -69,10 +69,10 @@ basic_memory/services/service.py,sha256=V-d_8gOV07zGIQDpL-Ksqs3ZN9l3qf3HZOK1f_YN
69
69
  basic_memory/sync/__init__.py,sha256=ko0xLQv1S5U7sAOmIP2XKl03akVPzoY-a9m3TFPcMh4,193
70
70
  basic_memory/sync/file_change_scanner.py,sha256=4whJej6t9sxwUp1ox93efJ0bBHSnAr6STpk_PsKU6to,5784
71
71
  basic_memory/sync/sync_service.py,sha256=nAOX4N90lbpRJeq5tRR_7PYptIoWwhXMUljE7yrneF4,7087
72
- basic_memory/sync/utils.py,sha256=uc7VLK34HufKyKavGwTPGU-ARfoQr_jYbjs4fsmUvuo,1233
72
+ basic_memory/sync/utils.py,sha256=wz1Fe7Mb_M5N9vYRQnDKGODiMGcj5MEK16KVJ3eoQ9g,1191
73
73
  basic_memory/sync/watch_service.py,sha256=CtKBrP1imI3ZSEgJl7Ffi-JZ_oDGKrhiyGgs41h5QYI,7563
74
- basic_memory-0.2.20.dist-info/METADATA,sha256=1cxfH12qZIMVnvV5MdiPOAffU2paqQB0GFEpTDVWNBs,7540
75
- basic_memory-0.2.20.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
76
- basic_memory-0.2.20.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
77
- basic_memory-0.2.20.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
78
- basic_memory-0.2.20.dist-info/RECORD,,
74
+ basic_memory-0.3.0.dist-info/METADATA,sha256=ACdUnxrfMPaAGPhpaQsxlTktIJm-6Dqoyi3x8jBak4Q,7539
75
+ basic_memory-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
76
+ basic_memory-0.3.0.dist-info/entry_points.txt,sha256=IDQa_VmVTzmvMrpnjhEfM0S3F--XsVGEj3MpdJfuo-Q,59
77
+ basic_memory-0.3.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
78
+ basic_memory-0.3.0.dist-info/RECORD,,