forecastfactor-publisher 1.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.
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.2
2
+ Name: forecastfactor_publisher
3
+ Version: 1.0.0
4
+ Summary: A library for publishing forecast data to an API
5
+ Author: Ricardo Teixeira
6
+ Author-email: ricardo.teixeira@obiio.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.7
11
+ Requires-Dist: requests
12
+ Requires-Dist: pandas
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: requires-dist
17
+ Dynamic: requires-python
18
+ Dynamic: summary
@@ -0,0 +1,299 @@
1
+ # Forecast Factor Publisher
2
+
3
+ A Python library for publishing forecast data to the Forecast Factor API. This package provides a simple interface to upload time series data, forecasts, and associated metadata to the forecast ingestion service.
4
+
5
+ ## Features
6
+
7
+ - Upload raw time series data with metadata
8
+ - Publish forecast data with confidence bounds
9
+ - Include model information and performance metrics
10
+ - Support for turning points analysis
11
+ - Comprehensive error handling and validation
12
+
13
+ ## Installation
14
+
15
+ ### From PyPI (Recommended)
16
+
17
+ ```bash
18
+ pip install forecastfactor-publisher
19
+ ```
20
+
21
+ ### From Source
22
+
23
+ ```bash
24
+ git clone <repository-url>
25
+ cd forecastfactor_publisher
26
+ pip install -e .
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ import pandas as pd
33
+ from forecastfactor_publisher import forecastfactor_publish
34
+
35
+ # Prepare your data
36
+ raw_data = pd.DataFrame({
37
+ 'date': ['2023-01-01', '2023-01-02'],
38
+ 'value': [100, 110]
39
+ })
40
+
41
+ forecast_data = pd.DataFrame({
42
+ 'date': ['2023-02-01', '2023-02-02'],
43
+ 'value': [120, 130]
44
+ })
45
+
46
+ forecast_bounds = pd.DataFrame({
47
+ 'date': ['2023-02-01', '2023-02-02'],
48
+ 'lb95': [115, 125],
49
+ 'ub95': [125, 135]
50
+ })
51
+
52
+ forecast_residuals = pd.DataFrame({
53
+ 'date': ['2023-01-01', '2023-01-02'],
54
+ 'value': [0.1, -0.2]
55
+ })
56
+
57
+ # Define metadata
58
+ turning_points = {
59
+ "2023-01-15": ["peak", "trough"],
60
+ "2023-02-01": ["peak"]
61
+ }
62
+
63
+ metadata = {
64
+ "source": "internal_data",
65
+ "description": "Monthly sales forecast"
66
+ }
67
+
68
+ model_inputs = {
69
+ "algorithm": "ARIMA",
70
+ "mae": "0.15",
71
+ "rmse": "0.23"
72
+ }
73
+
74
+ model_info = {
75
+ "parameters": ["p=1", "d=1", "q=1"],
76
+ "features": ["lag_1", "trend"]
77
+ }
78
+
79
+ # Optionally, you can specify a custom API endpoint:
80
+ # result = forecastfactor_publish(..., base_url="https://your-custom-api-endpoint")
81
+
82
+ # Publish to API
83
+ result = forecastfactor_publish(
84
+ api_key="your_api_key_here",
85
+ group_name="sales_forecasts",
86
+ series_name="monthly_sales",
87
+ model_name="arima_111",
88
+ transformation_name="none",
89
+ data_frequency="monthly",
90
+ raw_data=raw_data,
91
+ forecast_data=forecast_data,
92
+ forecast_bounds=forecast_bounds,
93
+ forecast_residuals=forecast_residuals,
94
+ turning_points=turning_points,
95
+ metadata=metadata,
96
+ model_inputs=model_inputs,
97
+ model_info=model_info
98
+ )
99
+
100
+ print(result)
101
+ ```
102
+
103
+ ## API Reference
104
+
105
+ ### `forecastfactor_publish()`
106
+
107
+ Posts time series data and metadata to the Forecast Factor API.
108
+
109
+ #### Parameters
110
+
111
+ - **api_key** (str): API key for authentication
112
+ - **group_name** (str): The name of the group the series belongs to
113
+ - **series_name** (str): The name of the series
114
+ - **model_name** (str): The name of the model
115
+ - **transformation_name** (str): The transformation applied to the original dataset (e.g., 'none', 'log')
116
+ - **data_frequency** (str): The series data frequency (monthly, weekly, daily, etc.)
117
+ - **raw_data** (pd.DataFrame): DataFrame with columns ['date', 'value']
118
+ - **forecast_data** (pd.DataFrame): DataFrame with columns ['date', 'value']
119
+ - **forecast_bounds** (pd.DataFrame): DataFrame with columns ['date', 'lb95', ..., 'ub95']
120
+ - **forecast_residuals** (pd.DataFrame): DataFrame with columns ['date', 'value']
121
+ - **turning_points** (Dict): Dictionary where keys are timestamps, values are lists of turning points
122
+ - **metadata** (Dict): Additional metadata characterizing the series
123
+ - **model_inputs** (Dict): Information about the forecasting model and performance metrics
124
+ - **model_info** (Dict): Dictionary where keys are model parameters, values are lists of values
125
+ - - **base_url** (str, optional): Override the default API endpoint URL. Defaults to the official endpoint.
126
+
127
+ #### Returns
128
+
129
+ - **Dict**: Response from the API with status and message
130
+
131
+ ## Development
132
+
133
+ ### Prerequisites
134
+
135
+ - Python 3.7 or higher
136
+ - pip
137
+ - twine (for publishing)
138
+
139
+ ### Setup Development Environment
140
+
141
+ ```bash
142
+ # Clone the repository
143
+ git clone <repository-url>
144
+ cd forecastfactor_publisher
145
+
146
+ # Create virtual environment
147
+ python -m venv venv
148
+ source venv/bin/activate # On Windows: venv\Scripts\activate
149
+
150
+ # Install dependencies
151
+ pip install -r requirements.txt
152
+ pip install -e .
153
+ ```
154
+
155
+ ## Publishing New Versions
156
+
157
+ ### Step 1: Update Version Number
158
+
159
+ Before publishing a new version, you must update the version number in `setup.py`:
160
+
161
+ ```python
162
+ # In setup.py, line 5
163
+ version="0.1.9", # Increment this version number
164
+ ```
165
+
166
+ **Version Numbering Convention:**
167
+ - **Major.Minor.Patch** (e.g., 1.2.3)
168
+ - **Major**: Breaking changes
169
+ - **Minor**: New features, backward compatible
170
+ - **Patch**: Bug fixes, backward compatible
171
+
172
+ ### Step 2: Update Changelog (Optional but Recommended)
173
+
174
+ Create or update a `CHANGELOG.md` file to document changes:
175
+
176
+ ```markdown
177
+ # Changelog
178
+
179
+ ## [0.1.9] - 2024-01-15
180
+ ### Added
181
+ - New feature X
182
+ - Enhanced error handling
183
+
184
+ ### Fixed
185
+ - Bug fix Y
186
+
187
+ ## [0.1.8] - 2024-01-01
188
+ ### Added
189
+ - Initial release
190
+ ```
191
+
192
+ ### Step 3: Commit Changes
193
+
194
+ ```bash
195
+ git add .
196
+ git commit -m "Bump version to 0.1.9"
197
+ git tag v0.1.9
198
+ git push origin main
199
+ git push origin v0.1.9
200
+ ```
201
+
202
+ ### Step 4: Build and Publish
203
+
204
+ Use the provided release script:
205
+
206
+ ```bash
207
+ # Make sure you're in the project root directory
208
+ ./release.sh
209
+ ```
210
+
211
+ Or manually:
212
+
213
+ ```bash
214
+ # Clean old builds
215
+ rm -rf build dist *.egg-info
216
+
217
+ # Create new build
218
+ python3 setup.py sdist bdist_wheel
219
+
220
+ # Upload to PyPI
221
+ twine upload dist/*
222
+ ```
223
+
224
+ ### Step 5: Verify Publication
225
+
226
+ Check that your package is available on PyPI:
227
+
228
+ ```bash
229
+ pip install --upgrade forecastfactor-publisher
230
+ ```
231
+
232
+ ## Configuration
233
+
234
+ ### PyPI Credentials
235
+
236
+ Before publishing, ensure you have PyPI credentials configured:
237
+
238
+ ```bash
239
+ # Create ~/.pypirc file
240
+ [distutils]
241
+ index-servers =
242
+ pypi
243
+
244
+ [pypi]
245
+ repository = https://upload.pypi.org/legacy/
246
+ username = your_username
247
+ password = your_password
248
+ ```
249
+
250
+ Or use environment variables:
251
+
252
+ ```bash
253
+ export TWINE_USERNAME=your_username
254
+ export TWINE_PASSWORD=your_password
255
+ ```
256
+
257
+ ## Testing
258
+
259
+ ### Local Testing
260
+
261
+ ```bash
262
+ # Install in development mode
263
+ pip install -e .
264
+
265
+ # Test the package
266
+ python -c "from forecastfactor_publisher import forecastfactor_publish; print('Package imported successfully')"
267
+ ```
268
+
269
+ ### Test PyPI (Optional)
270
+
271
+ For testing before publishing to production PyPI:
272
+
273
+ ```bash
274
+ # Upload to test PyPI first
275
+ twine upload --repository testpypi dist/*
276
+
277
+ # Install from test PyPI
278
+ pip install --index-url https://test.pypi.org/simple/ forecastfactor-publisher
279
+ ```
280
+
281
+ ## Troubleshooting
282
+
283
+ ### Common Issues
284
+
285
+ 1. **Version Already Exists**: If you get an error about the version already existing, increment the version number in `setup.py`.
286
+
287
+ 2. **Authentication Failed**: Ensure your PyPI credentials are correct in `~/.pypirc` or environment variables.
288
+
289
+ 3. **Build Errors**: Make sure all dependencies are installed and the package structure is correct.
290
+
291
+ 4. **Import Errors**: Verify that `__init__.py` files are present in all directories.
292
+
293
+ ### Getting Help
294
+
295
+ If you encounter issues:
296
+
297
+ 1. Check the [PyPI documentation](https://packaging.python.org/)
298
+ 2. Verify your package structure matches Python packaging standards
299
+ 3. Test locally before publishing
@@ -0,0 +1 @@
1
+ from .publisher import forecastfactor_publish
@@ -0,0 +1,80 @@
1
+ import requests
2
+ import pandas as pd
3
+ from typing import Dict, Optional
4
+
5
+ def forecastfactor_publish(
6
+ api_key: str,
7
+ group_name: str,
8
+ series_name: str,
9
+ model_name: str,
10
+ transformation_name: str,
11
+ data_frequency: str,
12
+ raw_data: pd.DataFrame,
13
+ forecast_data: pd.DataFrame,
14
+ forecast_bounds: pd.DataFrame,
15
+ forecast_residuals: pd.DataFrame,
16
+ turning_points: Dict[str, list],
17
+ metadata: Dict[str, str],
18
+ model_inputs: Dict[str, str],
19
+ model_info: Dict[str, list],
20
+ base_url: Optional[str] = None,
21
+ ):
22
+ """
23
+ Posts time series data, metadata to an API.
24
+
25
+ Parameters:
26
+ api_key (str): API key for authentication.
27
+ group_name (str): The name of the group the series belongs to.
28
+ series_name (str): The name of the series.
29
+ model_name (str): The name of the model.
30
+ transformation_name (str): The name of the transformation of the original dataset to feed the model (e.g., 'none', 'log', etc.).
31
+ data_frequency (str): The series data frequency (monthly, weekly, daily, etc.).
32
+ raw_data (pd.DataFrame): DataFrame of raw time series data with columns ['date', 'value'].
33
+ forecast_data (pd.DataFrame): DataFrame of forecast bounds with columns ['date', 'value'].
34
+ forecast_bounds (pd.DataFrame): DataFrame of forecast data with columns ['date', 'lb95', ..., 'up95'].
35
+ forecast_residuals (pd.DataFrame): DataFrame of forecast data with columns ['date', 'value'].
36
+ turning_points (Dict): Dictionary where keys are timestamps, and values are lists of turning points.
37
+ metadata (Dict): Additional metadata characterizing the series and input parameters.
38
+ model_inputs (Dict): Information about the forecasting model, including performance metrics.
39
+ model_info (Dict): Dictionary where keys are model parameters, and values are lists of multiple values.
40
+ base_url (str, optional): Override the default API endpoint URL. Defaults to None (uses the official endpoint).
41
+
42
+ Returns:
43
+ Dict: Response from the API.
44
+ """
45
+ # Validate turning_points format
46
+ if not isinstance(turning_points, dict) or not all(isinstance(v, list) for v in turning_points.values()):
47
+ return {"status": "error", "message": "Invalid format: 'turningPoints' should be a dictionary with lists as values."}
48
+
49
+ # Validate model_info format
50
+ if not isinstance(model_info, dict) or not all(isinstance(v, list) for v in model_info.values()):
51
+ return {"status": "error", "message": "Invalid format: 'modelInfo' should be a dictionary with lists as values."}
52
+
53
+ payload = {
54
+ "groupName": group_name,
55
+ "seriesName": series_name,
56
+ "modelName": model_name,
57
+ "transformationName": transformation_name,
58
+ "dataFrequency": data_frequency,
59
+ "rawData": raw_data.to_dict(orient="records"),
60
+ "forecastData": forecast_data.to_dict(orient="records"),
61
+ "forecastBounds": forecast_bounds.to_dict(orient="records"),
62
+ "forecastResiduals": forecast_residuals.to_dict(orient="records"),
63
+ "turningPoints": turning_points,
64
+ "metadata": metadata,
65
+ "modelInfo": model_info,
66
+ "modelInputs": model_inputs,
67
+ }
68
+
69
+ headers = {
70
+ "Authorization": f"Bearer {api_key}",
71
+ "Content-Type": "application/json"
72
+ }
73
+
74
+ try:
75
+ url = base_url or "https://vu-forecast-ingestor.ricardofmteixeira.workers.dev"
76
+ response = requests.post(url, json=payload, headers=headers)
77
+ response.raise_for_status() # Raise HTTPError for bad responses (4xx, 5xx)
78
+ return {"status": "success", "message": "Forecast data successfully uploaded."}
79
+ except requests.exceptions.RequestException as e:
80
+ return {"status": "error", "message": f"Request failed: {str(e)}"}
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.2
2
+ Name: forecastfactor_publisher
3
+ Version: 1.0.0
4
+ Summary: A library for publishing forecast data to an API
5
+ Author: Ricardo Teixeira
6
+ Author-email: ricardo.teixeira@obiio.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.7
11
+ Requires-Dist: requests
12
+ Requires-Dist: pandas
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: requires-dist
17
+ Dynamic: requires-python
18
+ Dynamic: summary
@@ -0,0 +1,9 @@
1
+ README.md
2
+ setup.py
3
+ forecastfactor_publisher/__init__.py
4
+ forecastfactor_publisher/publisher.py
5
+ forecastfactor_publisher.egg-info/PKG-INFO
6
+ forecastfactor_publisher.egg-info/SOURCES.txt
7
+ forecastfactor_publisher.egg-info/dependency_links.txt
8
+ forecastfactor_publisher.egg-info/requires.txt
9
+ forecastfactor_publisher.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ forecastfactor_publisher
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="forecastfactor_publisher",
5
+ version="1.0.0",
6
+ description="A library for publishing forecast data to an API",
7
+ author="Ricardo Teixeira",
8
+ author_email="ricardo.teixeira@obiio.com",
9
+ packages=find_packages(include=["forecastfactor_publisher*"]),
10
+ install_requires=[
11
+ "requests",
12
+ "pandas",
13
+ ],
14
+ classifiers=[
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ],
19
+ python_requires=">=3.7",
20
+ )