TimeFeatures 1.0.18__tar.gz → 2.0.0__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 (84) hide show
  1. {timefeatures-1.0.18/TimeFeatures.egg-info → timefeatures-2.0.0}/PKG-INFO +3 -1
  2. {timefeatures-1.0.18 → timefeatures-2.0.0/TimeFeatures.egg-info}/PKG-INFO +3 -1
  3. {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/SOURCES.txt +11 -0
  4. {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/requires.txt +2 -0
  5. timefeatures-2.0.0/docs/changes.rst +121 -0
  6. timefeatures-2.0.0/docs/conf.py +62 -0
  7. timefeatures-2.0.0/docs/index.rst +97 -0
  8. timefeatures-2.0.0/docs/installation.rst +103 -0
  9. timefeatures-2.0.0/docs/widgets/load-from-db.rst +136 -0
  10. timefeatures-2.0.0/docs/widgets/save-to-db.rst +185 -0
  11. timefeatures-2.0.0/docs/widgets/time-feature-constructor.rst +182 -0
  12. timefeatures-2.0.0/docs/widgets/variable-dependency-graph.rst +160 -0
  13. {timefeatures-1.0.18 → timefeatures-2.0.0}/setup.py +3 -1
  14. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/.buildinfo +1 -1
  15. timefeatures-2.0.0/timefeatures/help_html/_sources/changes.rst.txt +121 -0
  16. timefeatures-2.0.0/timefeatures/help_html/_sources/index.rst.txt +97 -0
  17. timefeatures-2.0.0/timefeatures/help_html/_sources/installation.rst.txt +103 -0
  18. timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/load-from-db.rst.txt +136 -0
  19. timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +185 -0
  20. timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +182 -0
  21. timefeatures-2.0.0/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +160 -0
  22. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/alabaster.css +6 -1
  23. timefeatures-2.0.0/timefeatures/help_html/changes.html +241 -0
  24. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/genindex.html +42 -27
  25. timefeatures-2.0.0/timefeatures/help_html/index.html +226 -0
  26. timefeatures-2.0.0/timefeatures/help_html/installation.html +231 -0
  27. timefeatures-2.0.0/timefeatures/help_html/objects.inv +0 -0
  28. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/search.html +59 -44
  29. timefeatures-2.0.0/timefeatures/help_html/searchindex.js +1 -0
  30. timefeatures-2.0.0/timefeatures/help_html/widgets/load-from-db.html +261 -0
  31. timefeatures-2.0.0/timefeatures/help_html/widgets/save-to-db.html +318 -0
  32. timefeatures-2.0.0/timefeatures/help_html/widgets/time-feature-constructor.html +321 -0
  33. timefeatures-2.0.0/timefeatures/help_html/widgets/variable-dependency-graph.html +308 -0
  34. timefeatures-2.0.0/timefeatures/widgets/icons/loaddatadb.svg +1 -0
  35. timefeatures-2.0.0/timefeatures/widgets/owloadfromdb.py +553 -0
  36. timefeatures-2.0.0/timefeatures/widgets/owsavetodb.py +850 -0
  37. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/owtimefeaturesconstructor.py +8 -6
  38. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/owvardependencygraph.py +58 -9
  39. timefeatures-1.0.18/docs/conf.py +0 -26
  40. timefeatures-1.0.18/docs/index.rst +0 -37
  41. timefeatures-1.0.18/docs/widgets/save-to-db.rst +0 -70
  42. timefeatures-1.0.18/docs/widgets/time-feature-constructor.rst +0 -100
  43. timefeatures-1.0.18/docs/widgets/variable-dependency-graph.rst +0 -66
  44. timefeatures-1.0.18/timefeatures/help_html/_sources/index.rst.txt +0 -37
  45. timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/save-to-db.rst.txt +0 -70
  46. timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt +0 -100
  47. timefeatures-1.0.18/timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt +0 -66
  48. timefeatures-1.0.18/timefeatures/help_html/index.html +0 -135
  49. timefeatures-1.0.18/timefeatures/help_html/objects.inv +0 -6
  50. timefeatures-1.0.18/timefeatures/help_html/searchindex.js +0 -1
  51. timefeatures-1.0.18/timefeatures/help_html/widgets/save-to-db.html +0 -185
  52. timefeatures-1.0.18/timefeatures/help_html/widgets/time-feature-constructor.html +0 -219
  53. timefeatures-1.0.18/timefeatures/help_html/widgets/variable-dependency-graph.html +0 -181
  54. timefeatures-1.0.18/timefeatures/widgets/owsavetodb.py +0 -401
  55. {timefeatures-1.0.18 → timefeatures-2.0.0}/LICENSE +0 -0
  56. {timefeatures-1.0.18 → timefeatures-2.0.0}/MANIFEST.in +0 -0
  57. {timefeatures-1.0.18 → timefeatures-2.0.0}/README.md +0 -0
  58. {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/dependency_links.txt +0 -0
  59. {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/entry_points.txt +0 -0
  60. {timefeatures-1.0.18 → timefeatures-2.0.0}/TimeFeatures.egg-info/top_level.txt +0 -0
  61. {timefeatures-1.0.18 → timefeatures-2.0.0}/docs/Makefile +0 -0
  62. {timefeatures-1.0.18 → timefeatures-2.0.0}/docs/requirements.txt +0 -0
  63. {timefeatures-1.0.18 → timefeatures-2.0.0}/imgs/installation.png +0 -0
  64. {timefeatures-1.0.18 → timefeatures-2.0.0}/imgs/workflow.png +0 -0
  65. {timefeatures-1.0.18 → timefeatures-2.0.0}/setup.cfg +0 -0
  66. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/__init__.py +0 -0
  67. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help.py +0 -0
  68. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/basic.css +0 -0
  69. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/custom.css +0 -0
  70. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/doctools.js +0 -0
  71. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/documentation_options.js +0 -0
  72. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/file.png +0 -0
  73. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/github-banner.svg +0 -0
  74. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/language_data.js +0 -0
  75. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/minus.png +0 -0
  76. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/plus.png +0 -0
  77. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/pygments.css +0 -0
  78. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/searchtools.js +0 -0
  79. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/help_html/_static/sphinx_highlight.js +0 -0
  80. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/__init__.py +0 -0
  81. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/graphgenerator.svg +0 -0
  82. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/savedatadb.svg +0 -0
  83. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/timefeature-xs.svg +0 -0
  84. {timefeatures-1.0.18 → timefeatures-2.0.0}/timefeatures/widgets/icons/timefeature.svg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TimeFeatures
3
- Version: 1.0.18
3
+ Version: 2.0.0
4
4
  Summary: Timefeatures add-on for Orange 3 data mining software.
5
5
  Home-page: https://github.com/alervgr/Orange-TimeFeatures
6
6
  Author: Alejandro Rivas García
@@ -23,7 +23,9 @@ Requires-Dist: AnyQt>=0.2.0
23
23
  Requires-Dist: PyQt5>=5.15.6
24
24
  Requires-Dist: PyQtWebEngine>=5.15.6
25
25
  Requires-Dist: scipy>=1.7.3
26
+ Requires-Dist: SQLAlchemy>=1.4.0
26
27
  Requires-Dist: psycopg2-binary>=2.9.9
28
+ Requires-Dist: PyMySQL>=1.0.0
27
29
  Requires-Dist: Orange3-Network>=1.8.0
28
30
  Provides-Extra: docs
29
31
  Requires-Dist: Sphinx>=7.0; extra == "docs"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: TimeFeatures
3
- Version: 1.0.18
3
+ Version: 2.0.0
4
4
  Summary: Timefeatures add-on for Orange 3 data mining software.
5
5
  Home-page: https://github.com/alervgr/Orange-TimeFeatures
6
6
  Author: Alejandro Rivas García
@@ -23,7 +23,9 @@ Requires-Dist: AnyQt>=0.2.0
23
23
  Requires-Dist: PyQt5>=5.15.6
24
24
  Requires-Dist: PyQtWebEngine>=5.15.6
25
25
  Requires-Dist: scipy>=1.7.3
26
+ Requires-Dist: SQLAlchemy>=1.4.0
26
27
  Requires-Dist: psycopg2-binary>=2.9.9
28
+ Requires-Dist: PyMySQL>=1.0.0
27
29
  Requires-Dist: Orange3-Network>=1.8.0
28
30
  Provides-Extra: docs
29
31
  Requires-Dist: Sphinx>=7.0; extra == "docs"
@@ -10,9 +10,12 @@ TimeFeatures.egg-info/entry_points.txt
10
10
  TimeFeatures.egg-info/requires.txt
11
11
  TimeFeatures.egg-info/top_level.txt
12
12
  docs/Makefile
13
+ docs/changes.rst
13
14
  docs/conf.py
14
15
  docs/index.rst
16
+ docs/installation.rst
15
17
  docs/requirements.txt
18
+ docs/widgets/load-from-db.rst
16
19
  docs/widgets/save-to-db.rst
17
20
  docs/widgets/time-feature-constructor.rst
18
21
  docs/widgets/variable-dependency-graph.rst
@@ -21,12 +24,17 @@ imgs/workflow.png
21
24
  timefeatures/__init__.py
22
25
  timefeatures/help.py
23
26
  timefeatures/help_html/.buildinfo
27
+ timefeatures/help_html/changes.html
24
28
  timefeatures/help_html/genindex.html
25
29
  timefeatures/help_html/index.html
30
+ timefeatures/help_html/installation.html
26
31
  timefeatures/help_html/objects.inv
27
32
  timefeatures/help_html/search.html
28
33
  timefeatures/help_html/searchindex.js
34
+ timefeatures/help_html/_sources/changes.rst.txt
29
35
  timefeatures/help_html/_sources/index.rst.txt
36
+ timefeatures/help_html/_sources/installation.rst.txt
37
+ timefeatures/help_html/_sources/widgets/load-from-db.rst.txt
30
38
  timefeatures/help_html/_sources/widgets/save-to-db.rst.txt
31
39
  timefeatures/help_html/_sources/widgets/time-feature-constructor.rst.txt
32
40
  timefeatures/help_html/_sources/widgets/variable-dependency-graph.rst.txt
@@ -43,14 +51,17 @@ timefeatures/help_html/_static/plus.png
43
51
  timefeatures/help_html/_static/pygments.css
44
52
  timefeatures/help_html/_static/searchtools.js
45
53
  timefeatures/help_html/_static/sphinx_highlight.js
54
+ timefeatures/help_html/widgets/load-from-db.html
46
55
  timefeatures/help_html/widgets/save-to-db.html
47
56
  timefeatures/help_html/widgets/time-feature-constructor.html
48
57
  timefeatures/help_html/widgets/variable-dependency-graph.html
49
58
  timefeatures/widgets/__init__.py
59
+ timefeatures/widgets/owloadfromdb.py
50
60
  timefeatures/widgets/owsavetodb.py
51
61
  timefeatures/widgets/owtimefeaturesconstructor.py
52
62
  timefeatures/widgets/owvardependencygraph.py
53
63
  timefeatures/widgets/icons/graphgenerator.svg
64
+ timefeatures/widgets/icons/loaddatadb.svg
54
65
  timefeatures/widgets/icons/savedatadb.svg
55
66
  timefeatures/widgets/icons/timefeature-xs.svg
56
67
  timefeatures/widgets/icons/timefeature.svg
@@ -3,7 +3,9 @@ AnyQt>=0.2.0
3
3
  PyQt5>=5.15.6
4
4
  PyQtWebEngine>=5.15.6
5
5
  scipy>=1.7.3
6
+ SQLAlchemy>=1.4.0
6
7
  psycopg2-binary>=2.9.9
8
+ PyMySQL>=1.0.0
7
9
  Orange3-Network>=1.8.0
8
10
 
9
11
  [docs]
@@ -0,0 +1,121 @@
1
+ Changelog
2
+ =========
3
+
4
+ Unreleased
5
+ ----------
6
+
7
+ **Load from DB (new widget)**
8
+
9
+ - Lists every dataset registered in the ``datasets`` metadata table
10
+ via SQLAlchemy and pulls the selected one back into Orange as an
11
+ ``Orange.data.Table`` using ``pandas.read_sql`` +
12
+ ``Orange.data.pandas_compat.table_from_frame``.
13
+ - Offers a Class column combo populated from the dataset's columns,
14
+ pre-selected with the user's persisted choice or the ``class_name``
15
+ recorded by Save to DB. The output ``Table`` already exposes the
16
+ chosen column as ``domain.class_var``, so no Select Columns widget
17
+ is needed downstream.
18
+ - Same dialect selector (PostgreSQL / MySQL), connection-status
19
+ label and ``QThread`` worker pattern as Save to DB. Both the
20
+ metadata listing and the actual table read happen off the GUI
21
+ thread.
22
+ - Workflow-persisted settings: ``selected_dataset`` and
23
+ ``selected_class`` are ``Setting(..., schema_only=True)``, restored
24
+ as soon as the connection comes back up on reload.
25
+
26
+ **Variable Dependency Graph**
27
+
28
+ - *New:* edges now carry **numeric weights** equal to the largest
29
+ ``|argument|`` among the temporal calls (``shift``, ``sum``, ``mean``,
30
+ ``count``, ``min``, ``max``, ``sd``) in the source expression that
31
+ reference the dependency. Plain (non-temporal) references default to
32
+ weight ``1``. The weights live in ``network.edges[0].edges.data``
33
+ and are consumable by any downstream Network widget.
34
+ - Refactor: flattened the ``from_row_col`` / ``grafo`` decorator pattern
35
+ into a single, documented ``build_dependency_network`` function.
36
+ - Performance: O(n³) → O(n²) by precomputing a ``name → index`` map and
37
+ using a ``set`` to dedupe dependencies.
38
+ - Bugfix: an ``IndexError`` was raised when the input domain had a
39
+ single column. The widget now checks ``len(domain) >= 2`` before
40
+ reading the second column.
41
+ - Removed 65 lines of dead commented-out code.
42
+
43
+ **Time Features Constructor**
44
+
45
+ - *Fixed (critical):* time-window functions used to lose context every
46
+ 5 000 rows because Orange chunks tables during ``transform``. The
47
+ widget now caches the full source per ``FeatureFunc`` and returns the
48
+ right slice for each chunk, so ``shift(x, -20)`` is correct across
49
+ chunk boundaries on datasets of any size.
50
+ - *Fixed:* "Variables to generate" was being cleared after every Send
51
+ and on every input change, so workflow save / reload lost the
52
+ definitions. Storage moved from ``ContextSetting`` to
53
+ ``Setting(..., schema_only=True)`` (matching upstream Orange v4) and
54
+ the editor is now restored from the persisted descriptors on every
55
+ input. The legacy context handler stays around to migrate old
56
+ workflows.
57
+ - Each **Send** re-transforms the *original* input table instead of the
58
+ cumulative output, removing the implicit "consume on Send" semantics
59
+ and the duplicate-name errors that came with it.
60
+ - ``eval`` hardened: ``__builtins__`` replaced with an empty dict in
61
+ the expression evaluator. Only the curated whitelist
62
+ (safe builtins + ``math`` + selected ``random`` / ``numpy``
63
+ helpers) is exposed.
64
+ - Refactor: ``modificar_expression`` collapsed from 7 near-identical
65
+ loops to a single regex-driven pass.
66
+ - Bugfix: ``FeatureEditor.editorData`` returned the variable name as
67
+ the expression.
68
+
69
+ **Save to DB**
70
+
71
+ - *New:* **MySQL support**. The connection panel now exposes a
72
+ database-type selector (PostgreSQL / MySQL). Per-dialect column
73
+ types and identifier quoting (``"name"`` vs ``\`name\```) live in
74
+ a ``_Dialect`` abstraction.
75
+ - *Performance:* uploads now go through
76
+ ``Orange.data.pandas_compat.table_to_frame`` +
77
+ ``DataFrame.to_sql(method='multi', chunksize=1000)`` over a
78
+ SQLAlchemy engine. The old row-per-INSERT loop is gone — typical
79
+ speedups are 50-100×, especially over the network. Identifier
80
+ quoting and per-column DDL types are emitted by the SQLAlchemy
81
+ dialect (``DOUBLE_PRECISION`` on PostgreSQL, ``DOUBLE`` on MySQL,
82
+ ``DATETIME`` instead of ``TIMESTAMP`` on MySQL to dodge the 2038
83
+ cap, ``VARCHAR(255)`` / ``TEXT`` everywhere else).
84
+ - *UX:* the upload runs in a background ``QThread`` (``_UploadWorker``),
85
+ so the canvas stays interactive on long writes. A status label under
86
+ the connection box reports *Not connected* / *Connected to … : …* /
87
+ *Uploading rows N/M…* / *Upload completed in Xs* / *Upload failed:
88
+ …* with colour cues. **Save**, **Connect** and the form fields are
89
+ disabled while the worker runs and re-enabled on success or
90
+ failure; the widget aborts the thread cleanly on close.
91
+ - *Fixed (critical):* SQL injection in the metadata ``INSERT``. The
92
+ query is now fully parametrised.
93
+ - Added an identifier whitelist
94
+ (``^[A-Za-z_][A-Za-z0-9_]{0,62}$``) and a ``quote_ident`` helper that
95
+ wraps identifiers with PostgreSQL-standard double quotes (with any
96
+ internal ``"`` doubled). Used in every ``CREATE TABLE`` / ``INSERT
97
+ INTO`` that touches user-supplied names.
98
+ - Replaced ``psycopg2`` with ``psycopg2-binary`` in the install
99
+ requirements so installation works on macOS, Linux and Windows
100
+ without a C compiler.
101
+ - ``setup.py`` now declares ``install_requires``; ``pip install`` was
102
+ previously not pulling in any runtime dependency.
103
+
104
+ Testing
105
+ -------
106
+
107
+ The widget suite grew to **92 tests**, covering:
108
+
109
+ - Unit tests for ``modificar_expression``, the time-window helpers,
110
+ ``_sanitize_name`` / ``_expression_or_none`` and ``_temporal_weights``.
111
+ - A regression test for the 5 000-row chunk bug
112
+ (``shift(x, -20)`` over a 12 000-row table).
113
+ - ``eval``-safety tests asserting that ``__import__`` / ``open`` raise
114
+ ``NameError`` while ``sqrt`` / ``abs`` still resolve.
115
+ - Widget-level tests (via ``Orange.widgets.tests.base.WidgetTest``) for
116
+ descriptor persistence, including an end-to-end
117
+ ``settingsHandler.pack_data`` / ``stored_settings=`` round-trip that
118
+ mirrors what Orange does when saving and reopening a ``.ows`` file.
119
+ - Edge-weight tests covering single calls, three-argument families,
120
+ mixed temporal / non-temporal references, max across multiple calls,
121
+ and per-dependency independence.
@@ -0,0 +1,62 @@
1
+ """Sphinx configuration for TimeFeatures."""
2
+
3
+ from pathlib import Path
4
+ import sys
5
+
6
+ ROOT = Path(__file__).resolve().parents[1]
7
+ sys.path.insert(0, str(ROOT))
8
+
9
+ # -- Project information --------------------------------------------------
10
+ project = "TimeFeatures"
11
+ author = "Alejandro Rivas Garcia"
12
+ copyright = "2026, Alejandro Rivas Garcia"
13
+ release = "1.0.18"
14
+ version = ".".join(release.split(".")[:2])
15
+
16
+ # -- General configuration ------------------------------------------------
17
+ extensions = [
18
+ # Auto-generate :ref: labels from section titles so we can write
19
+ # `:ref:`Edge Weights`` instead of declaring labels by hand.
20
+ "sphinx.ext.autosectionlabel",
21
+ # Link to Orange / NumPy / SciPy reference docs.
22
+ "sphinx.ext.intersphinx",
23
+ ]
24
+
25
+ # Prefix labels with the document name so two pages can share the same
26
+ # section title (e.g. "Usage Example") without clashing.
27
+ autosectionlabel_prefix_document = True
28
+
29
+ intersphinx_mapping = {
30
+ "python": ("https://docs.python.org/3", None),
31
+ "numpy": ("https://numpy.org/doc/stable/", None),
32
+ "scipy": ("https://docs.scipy.org/doc/scipy/", None),
33
+ "orange": ("https://orange3.readthedocs.io/projects/orange-data-mining-library/en/latest/", None),
34
+ }
35
+
36
+ templates_path = ["_templates"]
37
+ exclude_patterns = ["build", "Thumbs.db", ".DS_Store"]
38
+
39
+ language = "en"
40
+
41
+ # -- HTML output ----------------------------------------------------------
42
+ html_theme = "alabaster"
43
+ html_static_path = []
44
+ html_title = "TimeFeatures documentation"
45
+ html_short_title = "TimeFeatures"
46
+ html_theme_options = {
47
+ "description": (
48
+ "Time-series feature engineering for Orange3: build derived "
49
+ "variables, visualise their dependencies, and persist data to "
50
+ "PostgreSQL."
51
+ ),
52
+ "github_user": "alervgr",
53
+ "github_repo": "Orange-TimeFeatures",
54
+ "github_banner": True,
55
+ "show_powered_by": False,
56
+ "fixed_sidebar": True,
57
+ }
58
+
59
+ # Default replacements for any RST file (no need to redeclare per page).
60
+ rst_prolog = """
61
+ .. |addon| replace:: TimeFeatures
62
+ """
@@ -0,0 +1,97 @@
1
+ TimeFeatures
2
+ ============
3
+
4
+ |addon| is an `Orange3 <https://orangedatamining.com/>`_ add-on for
5
+ time-series feature engineering. It ships four widgets that work
6
+ together to define, visualise, persist and re-load derived variables
7
+ built on top of an existing dataset.
8
+
9
+ .. list-table::
10
+ :header-rows: 1
11
+ :widths: 30 70
12
+
13
+ * - Widget
14
+ - What it does
15
+ * - :doc:`widgets/time-feature-constructor`
16
+ - Defines new variables from existing ones using Python-style
17
+ expressions and time-window functions (``shift``, ``sum``,
18
+ ``mean``, ``min``, ``max``, ``sd``, ``count``).
19
+ * - :doc:`widgets/variable-dependency-graph`
20
+ - Builds a directed, **weighted** dependency graph from the
21
+ resulting variable / expression table. Edge weights summarise
22
+ how far back or forward in time each variable looks.
23
+ * - :doc:`widgets/save-to-db`
24
+ - Persists the resulting dataset to a SQL database (PostgreSQL
25
+ or MySQL), with full SQL-injection defences and an optional
26
+ completion email.
27
+ * - :doc:`widgets/load-from-db`
28
+ - Lists the datasets previously stored by Save to DB and pulls
29
+ the chosen one back into Orange, optionally marking the class
30
+ column directly so no Select Columns widget is needed.
31
+
32
+ .. _workflow:
33
+
34
+ Workflow
35
+ --------
36
+
37
+ A typical pipeline:
38
+
39
+ .. code-block:: text
40
+
41
+ File → Time Features Constructor → ┬→ <downstream models>
42
+ └→ Variable Dependency Graph
43
+
44
+ Network Explorer
45
+
46
+ The **Time Features Constructor** outputs both the transformed data
47
+ (top arrow) and the variable / expression definition table (bottom
48
+ arrow). Feed the latter into the **Variable Dependency Graph** to
49
+ visualise the dependencies, and send the data into **Save to DB** if
50
+ you want to keep it in a database.
51
+
52
+ Getting started
53
+ ---------------
54
+
55
+ .. toctree::
56
+ :maxdepth: 2
57
+
58
+ installation
59
+
60
+ .. _widgets:
61
+
62
+ Widgets
63
+ -------
64
+
65
+ .. toctree::
66
+ :maxdepth: 1
67
+
68
+ widgets/time-feature-constructor
69
+ widgets/variable-dependency-graph
70
+ widgets/save-to-db
71
+ widgets/load-from-db
72
+
73
+ Project
74
+ -------
75
+
76
+ .. toctree::
77
+ :maxdepth: 1
78
+
79
+ changes
80
+
81
+ Building this documentation
82
+ ---------------------------
83
+
84
+ .. code-block:: bash
85
+
86
+ pip install -e ".[docs]"
87
+ python -m sphinx -b html docs docs/build/html
88
+
89
+ The HTML build is also bundled with the wheel so Orange's in-app help
90
+ panel can resolve every widget's *Help* action without internet
91
+ access.
92
+
93
+ Indices
94
+ -------
95
+
96
+ * :ref:`genindex`
97
+ * :ref:`search`
@@ -0,0 +1,103 @@
1
+ Installation
2
+ ============
3
+
4
+ |addon| is an Orange3 add-on, so it requires a working Orange3
5
+ installation in the same Python environment.
6
+
7
+ From PyPI
8
+ ---------
9
+
10
+ .. code-block:: bash
11
+
12
+ pip install TimeFeatures
13
+
14
+ This pulls in every runtime dependency, including the precompiled
15
+ ``psycopg2-binary`` wheel so the **Save to DB** widget works on macOS,
16
+ Linux and Windows without a C toolchain.
17
+
18
+ From source
19
+ -----------
20
+
21
+ .. code-block:: bash
22
+
23
+ git clone https://github.com/alervgr/Orange-TimeFeatures.git
24
+ cd Orange-TimeFeatures
25
+ pip install -e .
26
+
27
+ The ``-e`` flag installs in *editable* mode so changes to the source
28
+ tree are picked up on the next Orange restart without reinstalling.
29
+
30
+ Inside Orange
31
+ -------------
32
+
33
+ |addon| also installs through Orange's GUI:
34
+
35
+ 1. Open Orange.
36
+ 2. Go to **Options → Add-ons…**.
37
+ 3. Tick **TimeFeatures** in the list and confirm.
38
+ 4. Restart Orange. The new widgets appear under the **Time-Features**
39
+ toolbox section.
40
+
41
+ .. image:: https://github.com/alervgr/Orange-TimeFeatures/blob/main/imgs/installation.png?raw=true
42
+ :alt: TimeFeatures in Orange's Add-on installer.
43
+
44
+ Anaconda
45
+ --------
46
+
47
+ The same ``pip install TimeFeatures`` command works inside a Conda
48
+ environment as long as Orange3 is installed there.
49
+
50
+ Dependencies
51
+ ------------
52
+
53
+ |addon| declares the following runtime dependencies (see
54
+ ``setup.py``):
55
+
56
+ .. list-table::
57
+ :header-rows: 1
58
+
59
+ * - Package
60
+ - Minimum version
61
+ - Used by
62
+ * - ``numpy``
63
+ - 1.22.4
64
+ - All widgets.
65
+ * - ``scipy``
66
+ - 1.7.3
67
+ - Sparse adjacency matrices in the dependency graph.
68
+ * - ``PyQt5``
69
+ - 5.15.6
70
+ - Widget UI.
71
+ * - ``AnyQt``
72
+ - 0.2.0
73
+ - Qt abstraction used by Orange.
74
+ * - ``SQLAlchemy``
75
+ - 1.4.0
76
+ - Dialect-agnostic SQL toolkit used by **Save to DB**.
77
+ * - ``psycopg2-binary``
78
+ - 2.9.9
79
+ - PostgreSQL driver for **Save to DB**.
80
+ * - ``PyMySQL``
81
+ - 1.0.0
82
+ - MySQL driver for **Save to DB**.
83
+ * - ``Orange3-Network``
84
+ - 1.8.0
85
+ - ``Network`` type produced by **Variable Dependency Graph**.
86
+
87
+ Orange3 itself is intentionally left out of the requirements list — the
88
+ host application provides it.
89
+
90
+ Running tests
91
+ -------------
92
+
93
+ The test suite uses ``unittest`` and lives under
94
+ ``timefeatures/widgets/tests/``. From a checkout:
95
+
96
+ .. code-block:: bash
97
+
98
+ pip install -e .
99
+ python -m unittest discover -v timefeatures/widgets/tests
100
+
101
+ The widget-level tests inherit from ``Orange.widgets.tests.base.WidgetTest``
102
+ and therefore require Qt; a virtual display (``Xvfb``) is enough on a
103
+ headless CI worker.
@@ -0,0 +1,136 @@
1
+ Load from DB
2
+ ============
3
+
4
+ The **Load from DB** widget is the inverse of :doc:`save-to-db`. It
5
+ connects to a SQL database, lists the datasets previously persisted by
6
+ **Save to DB**, and pulls the selected one back into Orange as a
7
+ ``Table`` — optionally marking the class column on the fly so no
8
+ **Select Columns** widget is needed downstream.
9
+
10
+ Inputs
11
+ ------
12
+
13
+ This widget has no input signals.
14
+
15
+ Outputs
16
+ -------
17
+
18
+ .. list-table::
19
+ :header-rows: 1
20
+
21
+ * - Signal
22
+ - Type
23
+ - Description
24
+ * - Data
25
+ - ``Orange.data.Table``
26
+ - The loaded dataset. If the user picks a class column, the
27
+ resulting domain already exposes it as the class variable; all
28
+ other columns stay in ``domain.attributes`` and the metas
29
+ declared in the SQL schema (if any) remain as ``domain.metas``.
30
+
31
+ Controls
32
+ --------
33
+
34
+ .. list-table::
35
+ :header-rows: 1
36
+
37
+ * - Field
38
+ - Description
39
+ * - Database type
40
+ - Combo box at the top of the connection box. Pick **PostgreSQL**
41
+ or **MySQL**. The driver and quoting rules adapt automatically
42
+ through the same :class:`_Dialect` abstraction the **Save to
43
+ DB** widget uses.
44
+ * - Connection status
45
+ - Small label under the connection box. Shows three states:
46
+ neutral ("Not connected", "Connecting…", "Listing datasets…",
47
+ "Loading <name>…"), success ("Connected to PostgreSQL:
48
+ host/db (N datasets)", "Loaded <name> (N rows)"), error
49
+ ("Connection failed: …", "Load failed: …").
50
+ * - Dataset
51
+ - Combo populated from ``SELECT * FROM datasets ORDER BY
52
+ datetime DESC``. The most recent upload comes first; the last
53
+ choice is restored when reopening a workflow.
54
+ * - Dataset info
55
+ - Read-only block under the combo: save timestamp, row/column
56
+ counts and the original class column recorded by **Save to DB**.
57
+ * - Class column
58
+ - Combo with every column of the selected dataset plus a
59
+ ``(no class)`` sentinel. Defaults to (1) the user's persisted
60
+ choice, (2) the ``class_name`` stored in the ``datasets``
61
+ metadata, (3) ``(no class)`` if none of the above apply.
62
+ * - Load
63
+ - Triggers the actual download.
64
+
65
+ How it Works
66
+ ------------
67
+
68
+ When the **Connect** button is clicked, the widget validates the
69
+ connection through ``OWBaseSql`` (the same path Save to DB uses) and
70
+ then spawns a background ``QThread`` that runs a
71
+ ``_ListDatasetsWorker``. The worker queries the ``datasets`` metadata
72
+ table via SQLAlchemy and emits the result back to the GUI thread.
73
+
74
+ Selecting a dataset triggers a tiny ``SELECT * FROM <name> LIMIT 0``
75
+ to fetch the column list — this is cheap enough to run synchronously
76
+ because the server only returns the column header.
77
+
78
+ When **Load** is clicked, a ``_LoadTableWorker`` runs
79
+ ``pandas.read_sql("SELECT * FROM <name>", engine)`` on a background
80
+ thread, returning a DataFrame that the GUI thread converts into an
81
+ ``Orange.data.Table`` with
82
+ ``Orange.data.pandas_compat.table_from_frame``. If the user picked a
83
+ class column, the helper ``_build_domain_with_class`` rebuilds the
84
+ domain so that column becomes ``domain.class_var`` and the rest of the
85
+ columns stay in ``domain.attributes``.
86
+
87
+ While any worker runs, the form controls (database type, connection
88
+ fields, **Connect**, **Load**, dataset and class combos) are
89
+ temporarily disabled and the status label keeps the user informed.
90
+
91
+ Workflow Persistence
92
+ --------------------
93
+
94
+ Two ``Setting``\\s are persisted with the workflow:
95
+
96
+ - ``selected_dataset`` — the name picked in the Dataset combo.
97
+ - ``selected_class`` — the name picked in the Class combo
98
+ (``""`` means "no class").
99
+
100
+ Both are declared as ``Setting(..., schema_only=True)``, mirroring the
101
+ **Time Features Constructor** convention: the values live in the
102
+ ``.ows`` file but never become global defaults. On reopening a
103
+ workflow, the widget restores the choices as soon as the connection
104
+ succeeds and the dataset list arrives.
105
+
106
+ Usage Example
107
+ -------------
108
+
109
+ Round-tripping a dataset through the database:
110
+
111
+ 1. In one Orange workflow, attach a **File** widget to **Save to DB**
112
+ and upload the data with a chosen table name.
113
+ 2. In another workflow (or the same one), drop a **Load from DB**
114
+ widget.
115
+ 3. Pick the database type, fill in the connection fields, and click
116
+ **Connect**.
117
+ 4. Pick the dataset in the Dataset combo. The info block shows the
118
+ timestamp and the original class.
119
+ 5. Override the Class column if you want a different target, or leave
120
+ the default to keep the original one.
121
+ 6. Click **Load**. The table flows out of the **Data** output ready
122
+ for any downstream Orange widget — no **Select Columns** in
123
+ between.
124
+
125
+ Requirements
126
+ ------------
127
+
128
+ |addon| brings every dependency the widget needs:
129
+
130
+ .. code-block:: text
131
+
132
+ SQLAlchemy>=1.4.0 # dialect-agnostic SQL toolkit
133
+ psycopg2-binary>=2.9.9 # PostgreSQL driver
134
+ PyMySQL>=1.0.0 # MySQL driver
135
+
136
+ ``pandas`` itself is a transitive dependency of Orange3.