tokenator 0.1.1__tar.gz → 0.1.3__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tokenator
3
- Version: 0.1.1
3
+ Version: 0.1.3
4
4
  Summary: Token usage tracking wrapper for LLMs
5
5
  License: MIT
6
6
  Author: Ujjwal Maheshwari
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "tokenator"
3
- version = "0.1.1"
3
+ version = "0.1.3"
4
4
  description = "Token usage tracking wrapper for LLMs"
5
5
  authors = ["Ujjwal Maheshwari <your.email@example.com>"]
6
6
  readme = "README.md"
@@ -0,0 +1,20 @@
1
+ """Tokenator - Track and analyze your OpenAI API token usage and costs."""
2
+
3
+ import logging
4
+ from .client_openai import OpenAIWrapper
5
+ from . import usage
6
+ from .utils import get_default_db_path, is_colab
7
+
8
+ __version__ = "0.1.0"
9
+ __all__ = ["OpenAIWrapper", "usage", "get_default_db_path"]
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ try:
14
+ if not is_colab():
15
+ from .migrations import check_and_run_migrations
16
+ check_and_run_migrations()
17
+ else:
18
+ logger.info("Running in Colab environment - skipping migrations")
19
+ except Exception as e:
20
+ logger.warning(f"Failed to run migrations, but continuing anyway: {e}")
@@ -0,0 +1,38 @@
1
+ """Automatic database migrations manager."""
2
+
3
+ import os
4
+ import logging
5
+ from pathlib import Path
6
+ from alembic import command
7
+ from alembic.config import Config
8
+ from alembic.runtime.migration import MigrationContext
9
+ from sqlalchemy import create_engine
10
+
11
+ from .utils import get_default_db_path
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+ def check_and_run_migrations():
16
+ """Check and run any pending database migrations."""
17
+ try:
18
+ db_path = get_default_db_path()
19
+ engine = create_engine(f"sqlite:///{db_path}")
20
+
21
+ # Create migrations table if it doesn't exist
22
+ with engine.connect() as conn:
23
+ context = MigrationContext.configure(conn)
24
+ current_rev = context.get_current_revision()
25
+
26
+ if current_rev is None:
27
+ # Run migrations
28
+ config = Config()
29
+ migrations_dir = os.path.join(os.path.dirname(__file__), "migrations")
30
+ config.set_main_option("script_location", migrations_dir)
31
+ config.set_main_option("sqlalchemy.url", f"sqlite:///{db_path}")
32
+
33
+ command.upgrade(config, "head")
34
+ logger.info("Database migrations completed successfully")
35
+ except Exception as e:
36
+ logger.error(f"Failed to run migrations: {e}")
37
+ # Don't raise the exception - allow the application to continue
38
+ # The user can manually initialize the DB later if needed
@@ -0,0 +1,49 @@
1
+ """Shared utility functions for tokenator."""
2
+
3
+ import os
4
+ import platform
5
+ import logging
6
+ from pathlib import Path
7
+ from typing import Optional
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ def is_colab() -> bool:
12
+ """Check if running in Google Colab."""
13
+ try:
14
+ import google.colab # type: ignore
15
+ return True
16
+ except ImportError:
17
+ return False
18
+
19
+ def get_default_db_path() -> str:
20
+ """Get the platform-specific default database path."""
21
+ system = platform.system().lower()
22
+
23
+ try:
24
+ if is_colab():
25
+ # We're in Colab - use current directory
26
+ db_path = os.path.join(os.getcwd(), "tokenator_usage.db")
27
+ elif system == "linux" or system == "darwin":
28
+ # Follow XDG Base Directory Specification
29
+ xdg_data_home = os.environ.get("XDG_DATA_HOME", "")
30
+ if not xdg_data_home:
31
+ xdg_data_home = os.path.join(str(Path.home()), ".local", "share")
32
+ db_path = os.path.join(xdg_data_home, "tokenator", "usage.db")
33
+ elif system == "windows":
34
+ # Use %LOCALAPPDATA% on Windows
35
+ local_app_data = os.environ.get("LOCALAPPDATA", "")
36
+ if not local_app_data:
37
+ local_app_data = os.path.join(str(Path.home()), "AppData", "Local")
38
+ db_path = os.path.join(local_app_data, "tokenator", "usage.db")
39
+ else:
40
+ db_path = os.path.join(str(Path.home()), ".tokenator", "usage.db")
41
+
42
+ # Create directory if it doesn't exist
43
+ os.makedirs(os.path.dirname(db_path), exist_ok=True)
44
+ return db_path
45
+ except (OSError, IOError) as e:
46
+ # Fallback to current directory if we can't create the default path
47
+ fallback_path = os.path.join(os.getcwd(), "tokenator_usage.db")
48
+ logger.warning(f"Could not create default db path, falling back to {fallback_path}. Error: {e}")
49
+ return fallback_path
@@ -1,12 +0,0 @@
1
- """Tokenator - Track and analyze your OpenAI API token usage and costs."""
2
-
3
- from .client_openai import OpenAIWrapper
4
- from . import usage
5
- from .utils import get_default_db_path
6
- from .migrations import check_and_run_migrations
7
-
8
- __version__ = "0.1.0"
9
- __all__ = ["OpenAIWrapper", "usage", "get_default_db_path"]
10
-
11
- # Run migrations on import
12
- check_and_run_migrations()
@@ -1,40 +0,0 @@
1
- """Automatic database migrations manager."""
2
-
3
- import os
4
- from pathlib import Path
5
- from alembic import command
6
- from alembic.config import Config
7
- from alembic.runtime.migration import MigrationContext
8
- from alembic.script import ScriptDirectory
9
- from sqlalchemy import create_engine
10
-
11
- from .utils import get_default_db_path
12
-
13
- def get_alembic_config():
14
- """Get Alembic config pointing to the package's migrations."""
15
- package_dir = Path(__file__).parent
16
- migrations_dir = package_dir / "migrations"
17
-
18
- alembic_cfg = Config()
19
- alembic_cfg.set_main_option("script_location", str(migrations_dir))
20
- alembic_cfg.set_main_option("sqlalchemy.url", f"sqlite:///{get_default_db_path()}")
21
-
22
- return alembic_cfg
23
-
24
- def check_and_run_migrations():
25
- """Check if migrations are needed and run them automatically."""
26
- engine = create_engine(f"sqlite:///{get_default_db_path()}")
27
-
28
- # Create migrations table if it doesn't exist
29
- with engine.connect() as conn:
30
- context = MigrationContext.configure(conn)
31
- current_rev = context.get_current_revision()
32
-
33
- # Get latest available revision
34
- config = get_alembic_config()
35
- script = ScriptDirectory.from_config(config)
36
- head_rev = script.get_current_head()
37
-
38
- # Run migrations if needed
39
- if current_rev != head_rev:
40
- command.upgrade(config, "head")
@@ -1,38 +0,0 @@
1
- """Shared utility functions for tokenator."""
2
-
3
- import os
4
- import platform
5
- from pathlib import Path
6
- from typing import Optional
7
-
8
- def get_default_db_path() -> str:
9
- """Get the platform-specific default database path.
10
-
11
- Returns:
12
- str: Path to the SQLite database file
13
-
14
- The path follows platform conventions:
15
- - Linux/macOS: ~/.local/share/tokenator/usage.db (XDG spec)
16
- - Windows: %LOCALAPPDATA%\\tokenator\\usage.db
17
- - Others: ~/.tokenator/usage.db
18
- """
19
- system = platform.system().lower()
20
-
21
- if system == "linux" or system == "darwin":
22
- # Follow XDG Base Directory Specification
23
- xdg_data_home = os.environ.get("XDG_DATA_HOME", "")
24
- if not xdg_data_home:
25
- xdg_data_home = os.path.join(str(Path.home()), ".local", "share")
26
- db_path = os.path.join(xdg_data_home, "tokenator", "usage.db")
27
- elif system == "windows":
28
- # Use %LOCALAPPDATA% on Windows
29
- local_app_data = os.environ.get("LOCALAPPDATA", "")
30
- if not local_app_data:
31
- local_app_data = os.path.join(str(Path.home()), "AppData", "Local")
32
- db_path = os.path.join(local_app_data, "tokenator", "usage.db")
33
- else:
34
- db_path = os.path.join(str(Path.home()), ".tokenator", "usage.db")
35
-
36
- # Create directory if it doesn't exist
37
- os.makedirs(os.path.dirname(db_path), exist_ok=True)
38
- return db_path
File without changes
File without changes