timber-common 0.2.3__tar.gz → 0.2.4__tar.gz

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.
Files changed (101) hide show
  1. {timber_common-0.2.3 → timber_common-0.2.4}/PKG-INFO +1 -1
  2. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/security/oauth_service.py +51 -12
  3. {timber_common-0.2.3 → timber_common-0.2.4}/pyproject.toml +1 -1
  4. {timber_common-0.2.3 → timber_common-0.2.4}/CHANGELOG.md +0 -0
  5. {timber_common-0.2.3 → timber_common-0.2.4}/LICENSE +0 -0
  6. {timber_common-0.2.3 → timber_common-0.2.4}/README.md +0 -0
  7. {timber_common-0.2.3 → timber_common-0.2.4}/common/__init__.py +0 -0
  8. {timber_common-0.2.3 → timber_common-0.2.4}/common/config/__init__.py +0 -0
  9. {timber_common-0.2.3 → timber_common-0.2.4}/common/config/model_loader.py +0 -0
  10. {timber_common-0.2.3 → timber_common-0.2.4}/common/engine/__init__.py +0 -0
  11. {timber_common-0.2.3 → timber_common-0.2.4}/common/engine/config_executor.py +0 -0
  12. {timber_common-0.2.3 → timber_common-0.2.4}/common/engine/operation_registry.py +0 -0
  13. {timber_common-0.2.3 → timber_common-0.2.4}/common/init.py +0 -0
  14. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/__init__.py +0 -0
  15. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/base.py +0 -0
  16. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/configs/__init__.py +0 -0
  17. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/core/__init.__.py +0 -0
  18. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/core/tag.py +0 -0
  19. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/core/user.py +0 -0
  20. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/factory.py +0 -0
  21. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/mixins.py +0 -0
  22. {timber_common-0.2.3 → timber_common-0.2.4}/common/models/registry.py +0 -0
  23. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/__init__.py +0 -0
  24. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/__init__.py +0 -0
  25. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/alphavantage.py +0 -0
  26. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/base.py +0 -0
  27. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/curated_data.py +0 -0
  28. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/polygon.py +0 -0
  29. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/stock.py +0 -0
  30. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_fetcher/yfinance.py +0 -0
  31. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/__init__.py +0 -0
  32. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/portfolio_metrics.py +0 -0
  33. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/returns.py +0 -0
  34. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/risk_metrics.py +0 -0
  35. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/standardization.py +0 -0
  36. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/data_processor/technical_indicators.py +0 -0
  37. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/db_service.py +0 -0
  38. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/encryption/__init__.py +0 -0
  39. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/encryption/field_encryption.py +0 -0
  40. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/gdpr/__init__.py +0 -0
  41. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/gdpr/deletion.py +0 -0
  42. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/inventory/__init__.py +0 -0
  43. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/inventory/available_capabilities.py +0 -0
  44. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/inventory/cached_capabilities.py +0 -0
  45. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/inventory/loader.py +0 -0
  46. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/__init__.py +0 -0
  47. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/base.py +0 -0
  48. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/cache.py +0 -0
  49. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/instances.py +0 -0
  50. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/manager.py +0 -0
  51. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/notification.py +0 -0
  52. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/research.py +0 -0
  53. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/session.py +0 -0
  54. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/persistence/tracker.py +0 -0
  55. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/security/__init__.py +0 -0
  56. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/vector/__init__.py +0 -0
  57. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/vector/auto_ingestion.py +0 -0
  58. {timber_common-0.2.3 → timber_common-0.2.4}/common/services/vector/tag_embedding.py +0 -0
  59. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/__init__.py +0 -0
  60. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/config.py +0 -0
  61. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/db_utils.py +0 -0
  62. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/helpers.py +0 -0
  63. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/time_helpers.py +0 -0
  64. {timber_common-0.2.3 → timber_common-0.2.4}/common/utils/validators.py +0 -0
  65. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/00_association_tables.yaml +0 -0
  66. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/cache_models.yaml +0 -0
  67. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/narrative_models.yaml +0 -0
  68. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/notification_models.yaml +0 -0
  69. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/oauth_models.yaml +0 -0
  70. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/portfolio_models.yaml +0 -0
  71. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/stock_research_models.yaml +0 -0
  72. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/user_preferences_models.yaml +0 -0
  73. {timber_common-0.2.3 → timber_common-0.2.4}/data/models/vector_db_models.yaml +0 -0
  74. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/DOCUMENTATION_INDEX.md +0 -0
  75. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/DOCUMENTATION_SUMMARY.md +0 -0
  76. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/PROGRESS_UPDATE.md +0 -0
  77. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/TIMBER_SESSION_API_REFERENCE.md +0 -0
  78. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/01_model_design_patterns.md +0 -0
  79. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/02_service_architecture.md +0 -0
  80. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/03_data_fetching_strategies.md +0 -0
  81. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/04_caching_strategies.md +0 -0
  82. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/05_error_handling.md +0 -0
  83. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/06_performance_optimization.md +0 -0
  84. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/best_practices/07_security_best_practices.md +0 -0
  85. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/design_guides/01_system_architecture.md +0 -0
  86. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/design_guides/02_config_driven_models.md +0 -0
  87. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/design_guides/03_persistence_layer.md +0 -0
  88. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/design_guides/04_vector_integration.md +0 -0
  89. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/design_guides/05_multi_app_support.md +0 -0
  90. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/01_getting_started.md +0 -0
  91. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/02_creating_models.md +0 -0
  92. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/03_using_services.md +0 -0
  93. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/04_financial_data_fetching.md +0 -0
  94. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/05_encryption_and_security.md +0 -0
  95. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/06_vector_search.md +0 -0
  96. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/07_gdpr_compliance.md +0 -0
  97. {timber_common-0.2.3 → timber_common-0.2.4}/documentation/how_to/08_testing_guide.md +0 -0
  98. {timber_common-0.2.3 → timber_common-0.2.4}/modules/__init__.py +0 -0
  99. {timber_common-0.2.3 → timber_common-0.2.4}/modules/config/custom_analysis.yaml +0 -0
  100. {timber_common-0.2.3 → timber_common-0.2.4}/modules/config/investing_operations_config.yaml +0 -0
  101. {timber_common-0.2.3 → timber_common-0.2.4}/modules/investing_operations.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: timber-common
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Configuration-driven persistence library with automatic encryption, caching, vector search, and GDPR compliance for Python applications
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -45,7 +45,7 @@ def _patch_oauth2_client_methods():
45
45
 
46
46
  # Check if method already exists
47
47
  if hasattr(OAuth2Client, 'check_endpoint_auth_method'):
48
- logger.info("OAuth2Client already has check_endpoint_auth_method")
48
+ logger.debug("OAuth2Client already has check_endpoint_auth_method")
49
49
  return
50
50
 
51
51
  import secrets
@@ -65,12 +65,12 @@ def _patch_oauth2_client_methods():
65
65
  # If client has a configured method, use it strictly
66
66
  if hasattr(self, 'token_endpoint_auth_method') and self.token_endpoint_auth_method:
67
67
  result = method == self.token_endpoint_auth_method
68
- logger.info(f"Client {self.client_id}: checking {method} against configured {self.token_endpoint_auth_method} = {result}")
68
+ logger.debug(f"Client {self.client_id}: checking {method} against configured {self.token_endpoint_auth_method} = {result}")
69
69
  return result
70
70
 
71
71
  # Otherwise allow common methods
72
72
  result = method in ['client_secret_post', 'client_secret_basic', 'none']
73
- logger.info(f"Client {self.client_id}: {method} allowed by default = {result}")
73
+ logger.debug(f"Client {self.client_id}: {method} allowed by default = {result}")
74
74
  return result
75
75
 
76
76
  return False
@@ -81,9 +81,25 @@ def _patch_oauth2_client_methods():
81
81
 
82
82
  def check_client_secret(self, client_secret):
83
83
  """Validate client secret using constant-time comparison"""
84
+ logger.debug(f"check_client_secret called for client {self.client_id}")
85
+ logger.debug(f"Has client_secret attribute: {hasattr(self, 'client_secret')}")
86
+
84
87
  if not self.has_client_secret():
88
+ logger.warning(f"Client {self.client_id} has no secret configured")
85
89
  return False
86
- return secrets.compare_digest(self.client_secret, client_secret)
90
+
91
+ stored_secret = self.client_secret
92
+ provided_secret = client_secret
93
+
94
+ logger.debug(f"Stored secret length: {len(stored_secret)}")
95
+ logger.debug(f"Provided secret length: {len(provided_secret)}")
96
+ logger.debug(f"Stored secret (first 10 chars): {stored_secret[:10]}...")
97
+ logger.debug(f"Provided secret (first 10 chars): {provided_secret[:10]}...")
98
+
99
+ result = secrets.compare_digest(stored_secret, provided_secret)
100
+ logger.debug(f"Secret comparison result: {result}")
101
+
102
+ return result
87
103
 
88
104
  def get_client_id(self):
89
105
  """Return the client_id"""
@@ -344,15 +360,22 @@ class ModularAuthorizationServer(AuthorizationServer):
344
360
 
345
361
  def query_client(self, client_id: str):
346
362
  """Implements the mandatory client query for Authlib."""
363
+ logger.debug(f"query_client called with client_id: {client_id}")
364
+
347
365
  OAuth2Client = _get_model('OAuth2Client')
348
366
  if not OAuth2Client:
367
+ logger.error("OAuth2Client model not found in registry")
349
368
  return None
350
369
 
351
370
  with db_service.session_scope() as session:
352
371
  client = session.query(OAuth2Client).filter_by(client_id=client_id).first()
353
372
  if client:
354
373
  session.expunge(client)
355
- logger.info(f"Found client: {client_id}")
374
+ logger.debug(f"Found client: {client_id}")
375
+ logger.debug(f"Client name: {getattr(client, 'client_name', 'N/A')}")
376
+ logger.debug(f"Client has secret: {bool(getattr(client, 'client_secret', None))}")
377
+ logger.debug(f"Client auth method: {getattr(client, 'token_endpoint_auth_method', 'N/A')}")
378
+ logger.debug(f"Client is_active: {getattr(client, 'is_active', 'N/A')}")
356
379
  else:
357
380
  logger.warning(f"Client not found: {client_id}")
358
381
  return client
@@ -394,6 +417,22 @@ class ModularAuthorizationServer(AuthorizationServer):
394
417
  This is required by Authlib but was not implemented, causing NotImplementedError.
395
418
  """
396
419
  return status_code, payload, headers
420
+
421
+ def send_signal(self, name, *args, **kwargs):
422
+ """
423
+ Send a signal/event notification.
424
+
425
+ Authlib uses this for hooks like 'after_authenticate_client'.
426
+ We don't need to do anything with signals for basic OAuth,
427
+ but the method must exist to avoid NotImplementedError.
428
+
429
+ Args:
430
+ name: Signal name (e.g., 'after_authenticate_client')
431
+ *args, **kwargs: Signal-specific arguments
432
+ """
433
+ logger.debug(f"Signal sent: {name}")
434
+ # Signals are optional - we don't need to do anything
435
+ pass
397
436
 
398
437
  def create_oauth2_request(self, request):
399
438
  """
@@ -579,35 +618,35 @@ class MyPasswordGrant(grants.ResourceOwnerPasswordCredentialsGrant):
579
618
  try:
580
619
  with db_service.session_scope() as session:
581
620
  # Find user by email
582
- logger.info(f"Querying for user with email: {username}")
621
+ logger.debug(f"Querying for user with email: {username}")
583
622
  user = session.query(User).filter_by(email=username).first()
584
623
 
585
624
  if not user:
586
625
  logger.warning(f"Password grant: User not found: {username}")
587
626
  # List available users for debugging
588
627
  all_users = session.query(User).all()
589
- logger.info(f"Available users in database: {[u.email for u in all_users[:5]]}")
628
+ logger.debug(f"Available users in database: {[u.email for u in all_users[:5]]}")
590
629
  return None
591
630
 
592
- logger.info(f"User found: {user.email}, ID: {user.id}")
631
+ logger.debug(f"User found: {user.email}, ID: {user.id}")
593
632
 
594
633
  # Check if user is active
595
634
  is_active = getattr(user, 'is_active', True)
596
- logger.info(f"User is_active: {is_active}")
635
+ logger.debug(f"User is_active: {is_active}")
597
636
 
598
637
  if not is_active:
599
638
  logger.warning(f"Password grant: User not active: {username}")
600
639
  return None
601
640
 
602
641
  # Verify password
603
- logger.info(f"Checking password for user: {username}")
642
+ logger.debug(f"Checking password for user: {username}")
604
643
 
605
644
  if not hasattr(user, 'check_password'):
606
645
  logger.error(f"User model has no check_password method!")
607
646
  return None
608
647
 
609
648
  password_valid = user.check_password(password)
610
- logger.info(f"Password validation result: {password_valid}")
649
+ logger.debug(f"Password validation result: {password_valid}")
611
650
 
612
651
  if not password_valid:
613
652
  logger.warning(f"Password grant: Invalid password for user: {username}")
@@ -615,7 +654,7 @@ class MyPasswordGrant(grants.ResourceOwnerPasswordCredentialsGrant):
615
654
 
616
655
  # Update last login
617
656
  if hasattr(user, 'update_last_login'):
618
- logger.info(f"Updating last login for user: {username}")
657
+ logger.debug(f"Updating last login for user: {username}")
619
658
  user.update_last_login()
620
659
  session.flush()
621
660
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "timber-common"
3
- version = "0.2.3"
3
+ version = "0.2.4"
4
4
  description = "Configuration-driven persistence library with automatic encryption, caching, vector search, and GDPR compliance for Python applications"
5
5
  authors = ["Pumulo Sikaneta <pumulo@gmail.com>"]
6
6
  maintainers = ["Pumulo Sikaneta <pumulo@gmail.com>"]
File without changes
File without changes