Meerschaum 1¶
Historical release notes for the 1.x series.
1.7.x Releases¶
Read release notes
The 1.7 series was short and sweet with a big focus on improving the web API. The highlight feature was the integrated webterm, and the series includes many bugfixes and improvements.
v1.7.3 – v1.7.4¶
-
Fix an issue with the local stack healthcheck. Due to some edge cases, the local stack
docker-compose.yamlfile would not be correctly formatted untiledit confighad been executed. This patch ensures the files are synced with each invocation ofstack. -
Fix an issue when running the local stack with non-default ports. Initializing a local stack with a different database port (e.g. 5433) now routes correctly within the Docker compose network (now patching to internal port to 5432).
-
Fix
upgrade mrsmbehavior. Recent changes tostackbroke the automaticstack pullwithinmrsm upgrade mrsm.
v1.7.2¶
-
Fix
role "root" does not existfrom stack logs. Although the healthcheck was working as expected, the log output was filled withError FATAL: role "root" does not exist. These errors have been fixed. -
Fix
MRSM_CONFIGbehavior when runningstart api --production. Starting the Web API throughgunicorn(i.e.--production) now respectsMRSM_CONFIG. This is useful for runningstack upwith non-default credentials. -
Added
--insecureas an alias for--no-auth. To compliment the newly added--secureflag, starting the Web API with--insecurewill bypass authentication. -
Bump default TimescaleDB version to PG15. The default TimescaleDB version for the Meerschaum stack is now
latest-pg15-oss. -
Pass sysargs to
docker composeviastackThis patch allows for jumping into theapicontainer:
- Added the API endpoint
/healthcheck. This is used to determine reachability and the health of the local stack.
v1.7.0 – v1.7.1¶
-
Remove
get_backtrack_data()for instance connectors. If provided, this method will still override the new generic implementation. -
Add
--keyfileand--certfilesupport. When starting the Web API, you may now run via HTTPS with--keyfileand--certfile. Older releases required the keys to be set inMRSM_CONFIG. This also brings SSL support for--production(Gunicorn). -
Add the Webterm to the Web Console. At long last, the webterm is embedded within the web console and is accessible from the Web API at the endpoint
/webterm. You must provide your active, authorized session ID to access to the Webterm. -
Add
--securetostart api. Starting the Web API with--securewill now disallow actions from non-administrators. This is recommend for shared deployments. -
Fixed the registration page on the Web API. Users should now be able to create accounts from Dockerized deployments.
-
Held back
dash-extensionsThe recent 1.0.2+ releases have shipped some broken changes, sodash-extensionsis held back to1.0.1until newer releases have been tested. -
Allow for digits in environment connectors. Connectors defined as environment variables may now have digits in the type.
-
Fixed
stackon Windows. -
Fixed a false error with background jobs.
-
Increased the minimum password length to 5.
1.6.x Releases¶
Read release notes
The biggest features of the 1.6.x series were all about chunking and adding support for syncing generators. The series was also full of minor bugfixes, contributing to an even more polished experience. It also was the first release to drop support for a Python version, formally deprecating Python 3.7.
v1.6.16 – v1.6.19¶
-
Add Pydantic v2 support The only feature which requires Pydantic v1 is the
--scheduleflag, which will throw a warning with a hint to install an older version. The underlying libraries for this feature should have Pydantic v2 support merged soon. -
Bump dependencies. This patch bumps the minimum required versions for
typing-extensions,rich,prompt-toolkit,rocketry,uvicorn,websockets, andfastapiand loosens the minimum version ofpydantic. -
Fix shell formatting on Windows 10. Some edge case issues have been patched for older versions of Windows.
v1.6.15¶
- Sync chunks in the
copy pipesaction. This will help with large out-of-memory pipes.
v1.6.14¶
-
Added healthchecks to
mrsm stack up. The internal Docker Compose file formrsm stackwas bumped to version 3.9, and secrets were replaced with environment variable references. -
Fixed
--no-authwhen starting the API. The commandmrsm start api --no-authnow correctly handles sessions.
v1.6.13¶
- Remove
\\u0000from strings when inserting into PostgreSQL. Replace both\0and\\u0000with empty strings when streaming rows into PostgreSQL.
v1.6.12¶
- Allow nested chunk generators. This patch more gracefully handles labels for situations with nested chunk generators and adds and explicit test for this scenario.
import meerschaum as mrsm
pipe = mrsm.Pipe('foo', 'bar', instance='sql:memory')
docs = [{'color': 'red'}, {'color': 'green'}]
num_chunks = 3
num_batches = 2
def build_chunks():
return (
[
{'chunk_ix': chunk_ix, **doc}
for doc in docs
]
for chunk_ix in range(num_chunks)
)
batches = (
(
[
{'batch_ix': batch_ix, **doc}
for doc in chunk
]
for chunk in build_chunks()
)
for batch_ix in range(num_batches)
)
pipe.sync(batches)
print(pipe.get_data())
# batch_ix chunk_ix color
# 0 0 0 red
# 1 0 0 green
# 2 0 1 red
# 3 0 1 green
# 4 0 2 red
# 5 0 2 green
# 6 1 0 red
# 7 1 0 green
# 8 1 1 red
# 9 1 1 green
# 10 1 2 red
# 11 1 2 green
v1.6.11¶
- Fix an issue with in-place syncing. When syncing a SQL pipe in-place with a backtrack interval, the interval is applied to the existing data stage to avoid inserting duplicate rows.
v1.6.9 – v1.6.10¶
-
Improve thread safety checks. Added checks for
IS_THREAD_SAFEto connectors to determine whether to use mutlithreading. -
Fix an issue with custom flags while syncing. This patch includes better handling of custom flags added from plugins during the syncing process.
v1.6.8¶
- Added
as_iteratortoPipe.get_data(). Passingas_iterator=True(oras_chunks) toPipe.get_data()returns a generator which returns chunks of Pandas DataFrames.
Each DataFrame is the result of a Pipe.get_data() call with intermediate datetime bounds between begin and end of size chunk_interval (default datetime.timedelta(days=1) for time-series / 100,000 IDs for integers).
import meerschaum as mrsm
pipe = mrsm.Pipe(
'a', 'b',
columns={'datetime': 'id'},
dtypes={'id': 'Int64'},
)
pipe.sync([
{'id': 0, 'color': 'red'},
{'id': 1, 'color': 'blue'},
{'id': 2, 'color': 'green'},
{'id': 3, 'color': 'yellow'},
])
### NOTE: due to non-inclusive end bounding,
### each chunk contains
### (chunk_interval - 1) rows.
chunks = pipe.get_data(
chunk_interval = 2,
as_iterator = True,
)
for chunk in chunks:
print(chunk)
# id color
# 0 0 red
# 1 1 blue
# id color
# 0 2 green
# 1 3 yellow
- Add server-side cursor support to
SQLConnector.read(). Ifchunk_hookis provided, keep an open cursor and stream the chunks one-at-a-time. This allows for processing very large out-of-memory data sets.
To return the results of the chunk_hook callable rather than a dataframe, pass as_hook_result=True to receive a list of values.
If as_iterator is provided or chunksize is None, then SQLConnector.read() reverts to the default client-side cursor implementation (which loads the entire result set into memory).
import meerschaum as mrsm
conn = mrsm.get_connector()
def process_chunk(df: 'pd.DataFrame', **kw) -> int:
return len(df)
results = conn.read(
"very_large_table",
chunk_hook = process_chunk,
as_hook_results = True,
chunksize = 100,
)
results[:2]
# [100, 100]
- Remove
--sync-chunksand set its behavior as default. Due to the above changes toSQLConnector.read(),sync_chunksnow defaults toTrueinPipe.sync(). You may disable this behavior with--chunksize 0.
v1.6.7¶
- Improve memory usage when syncing generators.
To more lazily sync chunks from generators,
pool.map()has been replaced withpool.imap().
v1.6.6¶
- Issue one
ALTER TABLEquery per column for SQLite, MSSQL, DuckDB, and Oracle SQL. SQLite and other flavors do not support multiple columns in anALTER TABLEquery. This patch addresses this behavior and adds a specific test for this scenario.
v1.6.5¶
- Allow pipes to sync DataFrame generators.
If
pipe.sync()receives a generator (forDataFrames, dictionaries, or lists), it will attempt to consume it and sync its chunks in parallel threads (this can be single-threaded with--workers 1). For SQL pipes, this will be capped at your configured pool size (default 5) minus the running number of threads.
This means you may now return generators to large transcations, such as reading a large CSV:
Any iterator of DataFrame-like chunks will work:
def fetch(pipe, **kw) -> Generator[List[Dict[str, Any]]]:
return (
[
{'id': 1, 'val': 10.0 * i},
{'id': 2, 'val': 20.0 * i},
] for i in range(10)
)
This new behavior has been added to SQLConnector.fetch() so you may now confidently sync very large tables between your databases.
NOTE: The default chunksize for SQL queries has been lowered to 100,000 from 1,000,000. You may alter this value with --chunksize or setting the value in MRSM{system:connectors:sql:chunksize} (you can also edit the default pool size here).
-
Fix edge case with SQL in-place syncs. Occasionally, a few docs would be duplicated when running in-place SQL syncs. This patch increases the fetch window size to mitigate the issue.
-
Remove
beginandendfromfilter_existing(). The keyword arguments were interfering with the determined datetime bounds, so this patch removes these flags (albeitbeginwas already ignored) to avoid confusion. Date bounds are solely determined from the contents of the DataFrame.
v1.6.4¶
- Allow for mixed UTC offsets in datetimes. UTC offsets are now applied to datetime values before timezone information is stripped, which should now reflect accurate values. This patch also fixes edge cases when different offsets are synced within the same transcation.
import meerschaum as mrsm
pipe = mrsm.Pipe('a', 'b', columns={'datetime': 'dt'})
pipe.sync([
{'dt': '2023-01-01 00:00:00+00:00'},
{'dt': '2023-01-02 00:00:00+01:00'},
])
pipe.get_data().to_dict(orient=records)
# [
# {'dt': Timestamp('2023-01-01 00:00:00')},
# {'dt': Timestamp('2023-01-01 23:00:00')}
# ]
- Allow skipping datetime detection.
The automatic datetime detection feature now respects a pipe's
dtypes; columns that aren't of typedatetime64[ns]will be ignored.
import meerschaum as mrsm
pipe = mrsm.Pipe('a', 'b', dtypes={'not-date': 'str'})
pipe.sync([
{'not-date': '2023-01-01 00:00:00'}
])
pipe.get_data().to_dict(orient=records)
# [
# {'not-date': '2023-01-01 00:00:00'}
# ]
- Added utility method
enforce_dtypes(). The DataFrame data type enforcement logic ofpipe.enforce_dtypes()has been exposed asmeerschaum.utils.misc.enforce_dtypes():
from meerschaum.utils.misc import enforce_dtypes
import pandas as pd
df = pd.DataFrame([{'a': '1'}])
enforce_dtypes(df, {'a': 'Int64'}).dtypes
# a Int64
# dtype: object
-
Performance improvements. Some of the unnecessarily immutable transformations have been replaced with more memory- and compute-efficient in-place operations. Other small improvements like better caching should also speed things up.
-
Removed noise from debug output. The virtual environment debug messages have been removed to make
--debugeasier to read. -
Better handle inferred datetime index. The inferred datetime index feature may now be disabled by setting
datetimetoNone. Improvements were made to be handle incorrectly identified indices. -
Improve dynamic dtypes for SQLite. SQLite doesn't allow for modifying column types but is usually dynamic with data types. A few edge cases have been solved with a workaround for altering the table's definition.
v1.6.3¶
- Fixed an issue with background jobs. A change had broken daemon functionality has been reverted.
v1.6.2¶
-
Virtual environment and
piptweaks. With upcoming changes topipcoming due to PEP 668, this patch sets the environment variablePIP_BREAK_SYSTEM_PACKAGESwhen executingpipinternally. All packages are installed within virtual environments exceptuvicorn,gunicorn, and those explicitly installed with a venv ofNone. -
Change how pipes are pretty-printed. Printing the attributes of a single pipe now highlights the keys in blue.
-
Fix an issue with
bootstrap pipesand plugins. When bootstrapping a pipe with a plugin connector, the plugin's virtual environment will now be activated while executing itsregister()function. -
Update dependencies. The minimum version of
duckdbwas bumped to0.7.1,duckdb-enginewas bumped to0.7.0, andpipwas lowered to22.0.4to accept older versions. Additionally,pandas==2.0.0rc1was tested and confirmed to work, so version 1.7.x of Meerschaum will likely require 2.0+ ofpandasto make use of its PyArrow backend.
v1.6.0 – v1.6.1¶
Breaking Changes
-
Dropped Python 3.7 support. The latest
pandasrequires 3.8+, so to use Pandas 1.5.x, we have to finally drop Python 3.7. -
Upgrade SQLAlchemy to 2.0.5+. This includes better transaction handling with connections. Other packages which use SQLAlchemy may not yet support 2.0+.
-
Removed
MQTTConnector. This was one of the original connectors but was never tested or used in production. It may be reintroduced via a futuremqttplugin.
Bugfixes and Improvements
- Stop execution when improper command-line arguments are passed in. Incorrect command-line arguments will now return an error. The previous behavior was to strip the flags and execute the action anyway, which was undesirable.
$ mrsm show pipes -c
💢 Invalid arguments:
show pipes -c
🛑 argument -c/-C/--connector-keys: expected at least one argument
-
Allow
bootstrap connectorto create custom connectors. Thebootstrap connectorwizard can now handle registering custom connectors. It uses theREQUIRED_ATTRIBUTESlist set in the custom connector class when determining what to ask for. -
Allow custom connectors to omit
__init__()If a connector is created via@make_connectorand doesn't have an__init__()function, the base one is used to create the connector with the correct type (derived from the class name) and verify theREQUIRED_ATTRIBUTESvalues if present. -
Infer a connector's
typefrom its class name. Thetypeof a connector is now determined from its class name (e.g.FooConnectorwould have a typefoo). When inheriting fromConnector, it is no longer required to explictly pass the type before the label. For backwards compatability, the legacy method still behaves as expected.
from meerschaum.connectors import (
Connector,
make_connector,
get_connector,
)
@make_connector
class FooConnector:
REQUIRED_ATTRIBUTES = ['username', 'password']
conn = get_connector(
'foo',
username = 'abc',
password = 'def',
)
-
Allow connectors to omit a
label. The default labelmainwill be used iflabelis omitted. -
Add
metakeys to connectors. Like pipes, themetaproperty of a connector returns a dictionary with the kwargs needed to reconstruct the connector.
conn = mrsm.get_connector('sql:temp', flavor='sqlite', database=':memory:')
print(conn.meta)
# {'type': 'sql', 'label': 'temp', 'database': ':memory:', 'flavor': 'sqlite'}
-
Remove
NULbytes when inserting into PostgreSQL. PostgreSQL doesn't supportNULbytes in text ('\0'), so these characters are removed from strings when copying into a table. -
Cache
pipe.exists()for 5 seconds. Repeated calls topipe.exists()will be sped up due to short-term caching. This cache is invalidated when syncing or dropping a pipe. -
Fix an edge case with subprocesses in headless environments. Checks were added to subprocesses to prevent using interactive features when no such features may be available (i.e.
termios). -
Added
pprint(),get_config(), andattempt_import()to the top-level namespace. Frequently used functionspprint(),get_config(), andattempt_import()have been promoted to the root level of themeerschaumnamespace, i.e.:
import meerschaum as mrsm
mrsm.pprint(mrsm.get_config('meerschaum'))
sqlalchemy = mrsm.attempt_import('sqlalchemy')
- Fix CLI for MSSQL. The interactive CLI has been fixed for Microsoft SQL Server.
1.5.x Releases¶
Read release notes
The 1.5.x series offered many great improvements, namely the ability to use an integer datetime axis and the addition of JSON columns.
v1.5.8 – v1.5.10¶
- Infer JSON columns from the first first non-null value. When determining complex columns (dictionaries or lists), the first non-null value of the dataframe is checked rather than the first row only. This accounts for documents which contain variable keys in the same sync, e.g.:
import meerschaum as mrsm
pipe = mrsm.Pipe('a', 'b')
pipe.sync([
{'a': {'b': 1}},
{'c': {'d': 2}},
])
-
Fix a bug when reconstructing JSON columns. When rebuilding JSON values after merging, a check is first performed if the value is in fact a string (sometimes
NULLSslip in). -
Increase the timeout when determining Python versions. This fixes some difficult-to-reproduce bugs on Windows.
v1.5.7¶
-
Replace
ast.literal_eval()withjson.loads()when filtering JSON columns. This patch replaces the use ofstrandast.literal_eval()withjson.dumps()andjson.loads()to preserve accuracy. -
Fix a subtle bug with subprocesses. The function
run_python_package()now better handles environment passing and raises a more verbose warning when something goes wrong. -
Allow columns with
'create'in the name. A security measure previously disallowed certain keywords when sanitizing input. Now columns are allowed to contain certain keywords.
v1.5.3 – v1.5.6¶
- Pipes now support syncing dictionaries and lists. Complex columns (dicts or lists) will now be preserved:
import meerschaum as mrsm
pipe = mrsm.Pipe('a', 'b')
pipe.sync([{'a': {'b': 1}}])
df = pipe.get_data()
print(df['a'][0])
# {'b': 1}
You can also force strings to be parsed by setting the data type to json:
import meerschaum as mrsm
pipe = mrsm.Pipe(
'foo', 'bar',
columns = {'datetime': 'id'},
dtypes = {'data': 'json', 'id': 'Int64'},
)
docs = [{'id': 1, 'data': '{"foo": "bar"}'}]
pipe.sync(docs)
df = pipe.get_data()
print(df['data'][0])
# {'foo': 'bar'}
For PostgreSQL-like databases (e.g. TimescaleDB), this is stored as JSONB under the hood. For all others, it's stored as the equivalent for TEXT.
-
Fixed determining the version when installing plugins. Like the
requiredlist, the__version__string must be explicitly set in order for the correct version to be determined. -
Automatically cast
postgrestopostgresqlWhen aSQLConnectoris built with a flavor ofpostgres, it will be automatically set topostgresql.
v1.5.0 – v1.5.2¶
- Pipes may now use integers for the
datetimecolumn. If you use an auto-incrementing integer as your primary key, you may now use that column as your pipe'sdatetimecolumn, just specify thedtypeas anInt64:
import meerschaum as mrsm
pipe = mrsm.Pipe(
'foo', 'bar',
instance = 'sql:memory',
columns = {
'datetime': 'id',
},
dtypes = {
'id': 'Int64',
},
)
pipe.sync([{'id': 1, 'foo': 'bar'}])
pipe.sync([{'id': 2, 'foo': 'baz'}])
This applies the same incremental range filtering logic as is normally done on the datetime axis.
- Allow for multiple plugins directories.
You may now set multiple directories for
MRSM_PLUGINS_DIR. All of the plugins contained in each directory will be symlinked together into a singlepluginsnamespace. To do this, just setMRSM_PLUGINS_DIRto a JSON-encoded list:
-
Better Windows support. At long last, the color issues plaguing Windows users have finally been resolved. Additionally, support for background jobs has been fixed on Windows, though the daemonization library I use is pretty hacky and doesn't make for the smoothest experience. But at least it works now!
-
Fixed unsafe TAR extraction. A PR about unsafe use of
tar.extractall()brought this issue to light. -
Fixed the blank logs bug in
show logs. Backtracking a couple lines before following the rest of the logs has been fixed. -
Requirements may include brackets. Python packages listed in a plugin's
requirementslist may now include brackets (e.g.meerschaum[api]). -
Enforce 1000 row limit in
SQLConnector.to_sql()for SQLite. When inserting rows, the chunksize of 1000 is enforced for SQLite (was previously enforced only for reading). -
Patch parameters from
--paramsinedit pipesandregister pipes. When editing or registering pipes, the value of--paramswill now be patched into the pipe's parameters. This should be very helpful when scripting. -
Fixed
edit users. This really should have been fixed a long time ago. The actionedit userswas broken due to a stray import left over from a major refactor. -
Fixed a regex bug when cleaning up packages.
- Removed
show guiandshow modules.
1.4.x Releases¶
Read release notes
The 1.4.x series brought some incredible, stable releases, and the highlight feature was in-place SQL syncs for massive performance improvement. The addition of temporary to Pipes also made using pipes in projects more accessible.
v1.4.14¶
- Added flag
temporarytoPipe(and--temporary). Pipes built withtemporary=True, will not create instance tables (pipes,users, andplugins) or be able to modify registration. This is particularly useful when creating pipes from existing tables when automatic registration is not desired.
import meerschaum as mrsm
import pandas as pd
conn = mrsm.get_connector('sql:temp', uri='postgresql://user:pass@localhost:5432/db')
### Simulating an existing table.
table_name = 'my_table'
conn.to_sql(
pd.DataFrame([{'id_column': 1, 'value': 1.0}]),
name = table_name,
)
### Create a temporary pipe with the existing table as its target.
pipe = mrsm.Pipe(
'foo', 'bar',
target = table_name,
temporary = True,
instance = conn,
columns = {
'id': 'id_column',
},
)
docs = [
{
"id_column": 1,
"value": 123.456,
"new_column": "hello, world!",
},
]
### Existing table `my_table` is synced without creating other tables
### or affecting pipes' registration.
pipe.sync(docs)
-
Fixed potential security of public instance tables. The API now refuses to sync or serve data if the target is a protected instance table (
pipes,users, orplugins). -
Added not-null check to
pipe.get_sync_time().Thedatetimecolumn should never contain null values, but just in case,pipe.get_sync_time()now passes a not-null check toparamsfor the datetime column. -
Removed prompt for
valuefrompipe.bootstrap(). The prompt for an optionalvaluecolumn has been removed from the bootstrapping wizard becausepipe.columnsis now largely used as a collection of indices rather than the original purpose of meta-columns. -
Pass
--debugand other flags incopy pipes. Command line flags are now passed to the new pipe when copying an existing pipe.
v1.4.12 – v1.4.13¶
-
Fixed an issue when syncing empty DataFrames (#95). When syncing an empty list of documents,
Pipe.filter_existing()would trigger pulling the entire table into memory. This patch adds a check if the dataframe is empty. -
Allow the
datetimecolumn to be omitted in thebootstrapwizard. Now that thedatetimeindex is optional, the bootstrapping wizard allows users to skip this index. -
Fixed a small issue when syncing to MySQL. Due to the addition of MySQL 5.7 support in v1.4.11, a slight edge case arose which broke SQL definitions. This patch fixes MySQL behavior when a
WHEREclause is present in the definition.
v1.4.11¶
-
Add support for older versions of MySQL. The
WITHkeyword for CTE blocks was not introduced until MySQL 8.0. This patch uses the older syntax for older versions of MySQL and MariaDB. MySQL 5.7 was added to the test suite. -
Allow for any iterable in
items_str()If an iterable other than a list is passed toitems_str(), it will convert to a list before building the string:
from meerschaum.utils.misc import items_str
print(items_str({'apples': 1, 'bananas': 2}, quotes=False)
# apples and bananas
-
Fixed an edge case with
datetimeset toNone. This patch will ignore the datetime index even if it was set explicitly toNone. -
Added
Pipe.children. To complementPipe.parents, setting the parameters keychildrento a list of pipes' keys will be treated the same asPipe.parents:
import meerschaum as mrsm
pipe = mrsm.Pipe(
'a', 'b',
parameters = {
'children': [
{
'connector': 'a',
'metric': 'b',
'location': 'c',
},
]
}
)
print(pipe.children)
# [Pipe('a', 'b', 'c')]
- Added support for
type:labelsyntax inmrsm.get_connector(). The factory functionmrsm.get_connector()expects the type and label as two arguments, but this patch allows for passing a single string with both arguments:
- Fixed more edge case bugs.
For example, converting to
Int64sometimes breaks with older versions ofpandas. This patch adds a workaround.
v1.4.10¶
-
Fixed an issue with syncing background jobs. The
--nameflag of background jobs with colliding with thenamekeyword argument ofSQLConnector.to_sql(). -
Fixed a datetime bounding issue when
datetimeindex is omitted. If the minimum datetime value of the incoming dataframe cannot be determined, do not bound theget_data()request. -
Keep existing parameters when registering plugin pipes. When a pipe is registered with a plugin as its connector, the return value of the
register()function will be patched with the existing in-memory parameters. -
Fixed a data type syncing issue. In cases where fetched data types do not match the data types in the pipe's table (e.g. automatic datetime columns), a bug has been patched to ensure the correct data types are enforced.
-
Added
Venvto the root namespace. Now you can access virtual environments directly frommrsm:
v1.4.9¶
- Fixed in-place syncs for aggregate queries. In-place SQL syncs which use aggregation functions are now handled correctly. This version addresses differences in column types between backtrack and new data. For example, the following query will now be correctly synced:
WITH days_src AS (
SELECT *, DATE_TRUNC('day', "datetime") AS days
FROM plugin_stress_test
)
SELECT days, AVG(val) AS avg_value
FROM days_src
GROUP BY days
-
Activate virtual environments for custom instance connectors. All pipe methods now activate virtual environments for custom instance connectors.
-
Improved database connection performance. Cold connections to a SQL database have been sped up by replacing
sqlalchemy_utilswith handwritten logic (JSON for PostgreSQL-like and SQLite). -
Fixed an issue with virtual environment verification in a portable environment. The portable build has been updated to Python 3.9.15, and this patch includes a check to determine the known
site-packagepath for a virtual environment ofNoneinstead of relying on the default usersite-packagesdirectory. -
Fixed some environment warnings when starting the API
v1.4.5 – v1.4.8¶
- Bugfixes and stability improvements.
These versions included several bugfixes, such as patching
--skip-check-existingfor in-place syncs and fixing the behavior of--params(build_where()).
v1.4.0 – v1.4.4¶
- Added in-place syncing for SQL pipes.
This feature is big (enough to warrant a new point release). When pipes with the same instance connector and data source connector are synced, the method
sync_pipe_inplace()is invoked. For SQL pipes, this means the entire syncing process will now happen entirely in SQL, which can lead to massive performance improvements.
import meerschaum as mrsm
import pandas as pd
conn = mrsm.get_connector('sql', 'local')
conn.to_sql(pd.DataFrame([{'a': 1}]), 'foo')
pipe = mrsm.Pipe(
"sql:local", "foo",
instance = "sql:local",
parameters = {
"query": "SELECT * FROM foo"
},
)
### This will no longer load table data into memory.
pipe.sync()
This applies even when the source table's schema changes, just like the dynamic columns feature added in v1.3.0.
To disable this behavior, run the command
edit config systemand set the value under the keysexperimental:inplace_synctofalse.
- Added negation to
--params. Thebuild_where()function now allows you to negate certain values when prefixed with an underscore (_):
-
Added
--paramsto SQL pipes' queries. Specifying parameters when syncing SQL pipes will add those constraints to the fetch stage. -
Skip invalid parameters in
--params. If a column does not exist in a pipe's table, the value will be ignored in--params. -
Fixed environment issue when starting the Web API with
gunicorn. - Added an emoji to the SQL Query option of the web console.
- Fixed an edge case with data type enforcement.
- Other bugfixes
1.3.x Releases¶
Read release notes
The 1.3.x series brought a tremendous amount of new features and stability improvements. Read below to see everything that was introduced!
v1.3.13¶
-
Fixed an issue when displaying backtrack data on the Web Console. Certain values like
pd.NAwould break the Recent Data view on the Web Console. Now the values are cast to strings before building the table. -
Added YAML and JSON support to editing parameters. YAML is now the default, and toggle buttons have been added to switch the encoding. Line numbers have also been added to the editors.
-
Removed the index column from the CSV downloader. When the download button is clicked, the dataframe's index column will be omitted from the CSV file.
-
Changed the download filename to
<target>.csv. The download process will now name the CSV file after the table rather than the pipe. -
Web Console improvements. The items in the actions builder now are presented with a monospace font. Actions and subactions will have underscores represented as spaces.
-
Activating the virtual environment
Nonewill not override your current working directory. This is especially useful when testing the API. Activating the virtual environmentNonewill insert behind your current working directory or''insys.path. -
Added WebSocket Secure Support. This has been coming a long time, so I'm proud to announce that the web console can now detect whether the client is connecting via HTTPS and (assuming the server has the appropriate proxy configuration) will connect via WSS.
v1.3.10 – v1.3.12¶
-
Fixed virtual environment issues when syncing. This one's a doozy. Before this patch, there would frequently be warnings and sometimes exceptions thrown when syncing a lot of pipes with a lot of threads. This kind of race condition can be hard to pin down, so this patch reworks the virtual environment resolution system by keeping track of which threads have activated the environments and refusing to deactivate if other threads still depend on the environment. To enforce this behavior, most manual ivocations of
activate_venv()were replaced with theVenvcontext manager. Finally, the last stage of each action is to clean up any stray virtual environments. Note: You may still run into the wrong version of a package being imported into your plugin if you're syncing a lot of plugins concurrently. -
Allow custom instance connectors to be selected on the web console. Provided all of the appropriate interface methods are implemented, selecting a custom instance connector from the instance dropdown should no longer throw an error.
-
Bugfixes and improvements to the virtual environment system. This patch should resolve your virtual environment woes but at a somewhat significant performance penalty. Oh well, 'tis the price we must pay for correct and determinstic code!
-
Fixed custom flags added by
add_plugin_argument(). Refactoring work to decouple plugins from the argument parser had the unintended side effect of skipping over custom flags until after sysargs had already been parsed. This patch ensures all plugins withadd_plugin_argumentin their root module will be loaded before parsing. -
Upgraded
dash-extensions,dash, anddash-bootstrap-components. At long last,dash-extensionswill no longer need to be held back. -
Added additional websockets endpoints. The endpoints
/ws,/dash/ws/, and/dashwsresolve to the same handler. This is to allow compatability with different versions ofdash-extensions. -
Allow for custom arguments to be added from outside plugins. The function
add_plugin_argument()will now accept arguments when executed from outside a plugin. -
Fixed
verify packages.
v1.3.6 – v1.3.9¶
- Allow for syncing multiple data types per column.
The highlight of this release is support for syncing multiple data types per column. When different data types are encountered, the underlying column will be converted to
TEXT:
import meerschaum as mrsm
pipe = mrsm.Pipe('a', 'b', instance='sql:memory')
pipe.sync([{'a': 1}])
print(pipe.get_data())
# a
# 0 1
pipe.sync([{'a': 'foo'}])
# a
# 0 1
# 1 foo
-
Cleaned up the Web Console. The web console's navbar is now more mobile-friendly, and a "sign out" button has been added.
-
Removed plugins import when checking for environment connectors. This should make some commands feel more snappy by lazy loading custom connectors.
- Fixed an issue with an updated versin of
uvicorn. - Fixed an issue with
docker-compose. - Fixed an issue with
FastAPIon Python 3.7. - Added support for Python 3.11.
- Renamed
meerschaum.actions.argumentstomeerschaum._internal.arguments.
v1.3.4 – v1.3.5¶
-
Define environment connectors with JSON or URIs. Connectors defined as environment variables may now have their attributes set as JSON in addition to a URI string.
-
Custom Connectors may now be defined as environment variables. You may now set environment variables for custom connectors defined via
@make_connector, e.g.:
- Allow for custom connectors to be instance connectors.
Add the property
IS_INSTANCE = Trueyour custom connector to add it to the official list of instance types:
from meerschaum.connectors import make_connector, Connector
@make_connector
class FooConnector(Connector):
IS_INSTANCE = True
def __init__(label: str, **kw):
super().__init__('foo', label, **kw)
-
Install packages for all plugins with
mrsm install required. The default behavior formrsm install requiredwith no plugins named is now to install dependencies for all plugins. -
Syncing bugfixes.
v1.3.2 – v1.3.3¶
- Fixed a bug with
beginandendbounds inPipe.get_data(). A safety measure was incorrectly checking if the quoted version of a column was inpipe.get_columns_types(), not the unquoted version. This patch restores functionality forpipe.get_data(). - Fixed an issue with an upgraded version of
SQLAlchemy. - Added a parameters editor the Web UI. You may now edit your pipes' parameters in the browser through the Web UI!
- Added a SQL query editor to the Web UI. Like the parameters editor, you can edit your pipes' SQL queries in the browser.
- Added a Sync Documents option to the Web UI. You can directly sync documents into pipes on the Web UI.
- Added the arguments
order,limit,begin_add_minutes, andend_add_minutestoPipe.get_data(). These new arguments will give you finer control over the data selection behavior. - Enforce consistent ordering of indices in
Pipe.get_data(). - Allow syncing JSON-encoded strings. This patch allows pipes to sync JSON strings without first needing them to be deserialized.
- Fixed an environment error with Ubuntu 18.04.
- Bumped
duckdbandduckdb-engine. - Added a basic CLI for
duckdb. This will probably be replaced later down the line.
v1.3.1¶
- Fixed data type enforcement issues. A serious bug in data type enforcement has been patched.
- Allow
Pipe.dtypesto be edited. You can now set keys inPipe.dtypesand persist them withPipe.edit(). - Added
Pipe.update().Pipe.update()is an alias toPipe.edit(interactive=False). Pipe.delete()no longer deletes local attributes. It still removesPipe.id, but local attributes will now remain intact.- Fixed dynamic columns on DuckDB. DuckDB does not allow for altering tables when indices are created, so this patch will drop and rebuild indices when tables are altered.
- Replaced
CLOBwithNVARCHAR(2000)on Oracle SQL. This may require migrating existing pipes to use the new data type. - Enforce integers are of type
INTEGERon Oracle SQL. Lots of data type enforcement has been added for Oracle SQL. - Removed datetime warnings when syncing pipes without a datetime column.
- Removed grabbing the current time for the sync time if a sync time cannot be determined.
v1.3.0: Dynamic Columns¶
Improvements
-
Syncing now handles dynamic columns. Syncing a pipe with new columns will trigger an
ALTER TABLEquery to append the columns to your table:import meerschaum as mrsm pipe = mrsm.Pipe('foo', 'bar', instance='sql:memory') pipe.sync([{'a': 1}]) print(pipe.get_data()) # a # 0 1 pipe.sync([{'b': 1}]) print(pipe.get_data()) # a b # 0 1 <NA> # 1 <NA> 1If you've specified index columns, you can use this feature to fill in
NULLvalues in your table: -
Add as many indices as you like. In addition to the special index column labels
datetime,id, andvalue, the values of all keys within thePipe.columnsdictionary will be treated as indices when creating and updating tables:import meerschaum as mrsm indices = {'micro': 'station', 'macro': 'country'} pipe = mrsm.Pipe('demo', 'weather', columns=indices, instance='sql:memory') docs = [{'station': 1, 'country': 'USA', 'temp_f': 80.6}] pipe.sync(docs) docs = [{'station': 1, 'country': 'USA', 'temp_c': 27.0}] pipe.sync(docs) print(pipe.get_data()) # station country temp_f temp_c # 0 1 USA 80.6 27.0 -
Added a default 60-second timeout for pipe attributes. All parameter properties (e.g.
Pipe.columns,Pipe.target,Pipe.dtypes, etc.) will sync with the instance every 60 seconds. The in-memory attributes will be patched on top of the database values, so your unsaved state won't be lost (persist your state withPipe.edit()). You can change the timeout duration withmrsm edit config pipesunder the keysattributes:local_cache_timeout_seconds. To disable this caching behavior, set the value tonull. -
Added custom indices and Pandas data types to the Web UI.
Breaking Changes
- Removed
Noneas default for uninitalized properties for pipes. Parameter properties likePipe.columns,Pipe.parameters, etc. will now always return a dictionary, even if a pipe is not registered. Pipe.get_columns()now setserrortoFalseby default. Pipes are now mostly index-agnostic, so these checks are no longer needed. This downgrades errors in several functions to just warnings, e.g.Pipe.get_sync_time().
Bugfixes
- Always quote tables that begin with underscores in Oracle.
- Always refresh the metadata when grabbing
sqlalchemytables for pipes to account for dynamic state.
1.2.x Releases¶
Read release notes
This series brought many industry-ready features, such as the @make_connector decorator, improvements to the virtual environment system, the environment variable MRSM_PLUGINS_DIR, and much more.
v1.2.9¶
- Added support for Windows junctions for virtual environments.
This included many changes to fix functionality on Windows. For example, the addition of the
MRSM_PLUGINS_DIRenvironment variable broke Meerschaum on Windows, because Windows requires administrator rights to create symlinks.
v1.2.8¶
- Custom connectors may now have
register(pipe)methods. Just like the module-levelregister(pipe)plugin function, custom connectors may also provide this function as a class member. - Print a traceback if
fetch(pipe)breaks. A more verbose traceback is printed if a plugin breaks during the syncing process. - Cleaned up
sync pipesoutput. This patch cleans up the syncing process's pretty output. - Respect
--noprettyinsync pipes. This flag will only print JSON-encoded dictionaries forsync pipes. Tracebacks may still interfere without standard output, however.
v1.2.5 – v1.2.7¶
Venvcontext managers do not deactivate previously activated venvs. You can safely useVenvwithout worrying about deactivating your previously activated environments.- Better handling of nested plugin dependencies.
Plugin.get_dependencies()will not trigger an import. If you want certainty about a plugin's required list, trigger an import manually. Otherwise, it will useast.literal_eval()to determine the required list from the source itself. This only works for statically setrequiredlists.- Provide rich traceback for broken plugins. If a plugin fails to import, a nice traceback is printed out in addition to a warning.
- Only cache
Pipe.dtypesif the pipe exists. - Pass current environment to subprocesses. This should retain any custom configuration you've set in the main process.
- Hard-code port 5432 as the target DB container port in the stack. Changing the host port now will not change the target port in the container.
- Fixed a bug with background jobs and
to_sql(). The--nameflag was conflicting withto_sql(). - Reimplemented
apply_patch_to_config(). This patch removescascadictas a vendored dependency and replaces it with a simpler implementation. - Removed network request for shell connectivity status. The shell now simply checks for the existence of the connector. This may occasionally print an inaccurate connection status, but the speed benefit is worth it.
- Moved
dilland other required dependencies into thesqldependency group. - Replaced
redenginewithrocketry. - Patched
Literalintotypingfor Python 3.7. - Fixed shell commands.
This includes falling back to
' '.joininstead ofshlex.joinfor Python 3.7.
v1.2.1 – v1.2.4¶
- Added the
@make_connectordecorator. Plugins may now extend the baseConnectorclass to provide custom connectors. For most cases, the built-inpluginconnector should work fine. This addition opens up the internal connector system so that plugin authors may now add new types. See below for a minimal example of a new connector class:
# ~/.config/meerschaum/plugins/example.py
from meerschaum.connectors import make_connector, Connector
REQUIRED_ATTRIBUTES = {'username', 'password'}
@make_connector
class FooConnector(Connector):
def __init__(self, label: str, **kw):
"""
Instantiate the base class and verify the required attributes are present.
"""
kw['label'] = label
super().__init__('foo', **kw)
self.verify_attributes(REQUIRED_ATTRIBUTES)
def fetch(self, pipe, **kw):
"""
Return a dataframe (or list of dicts / dict of lists).
The same as you would in a regular fetch plugin, except that now
we can store configuration within the connector itself.
"""
return [{self.username: '2020-01-01'}]
- Allow for omitting
datetimecolumn index. Thedatetimecolumn name is still highly recommended, but recent changes have allowed pipes to be synced without a dedicated datetime axis. Plenty of warnings will be thrown if you sync your pipes without specifying a datetime index. If a datetime column can be found, it will be used as the index.
import meerschaum as mrsm
### This will work but throw warnings.
mrsm.Pipe('foo', 'bar').sync([{'a': 1}])
v1.2.0¶
Improvements
-
Added the action
start connectors. This command allows you to wait until all of the specified connectors are available and accepting connections. This feature is very handy when paired with the newMRSM_SQL_XURI environment variables. -
Added
MRSM_PLUGINS_DIR. This one's been on my to-do list for quite a bit! You can now place your plugins in a dedicated, version-controlled directory outside of your root directory.
Like MRSM_ROOT_DIR, specify a path with the environment variable MRSM_PLUGINS_DIR:
- Allow for symlinking in URI environment variables. You may now reference configuration keys within URI variables:
-
Increased token expiration window to 12 hours. This should reduce the number of login requests needed.
-
Improved virtual environment verification. More edge cases have been addressed.
-
Symlink Meerschaum into
Pluginvirtual environments. If plugins do not specifyMeerschaumin therequiredlist, Meerschaum will be symlinked to the currently running package.
Breaking changes
-
API endpoints for registering and editing users changed. To comply with OAuth2 convention, the API endpoint for registering a user is now a url-encoded form submission to
/users/register(/user/editfor editing).You must upgrade both the server and client to v1.2.0+ to login to your API instances.
-
Replaced
meerschaum.utils.sql.update_query()withmeerschaum.utils.sql.get_update_queries(). The new function returns a list of query strings rather than a single query. These queries are executed within a single transaction.
Bugfixes
-
Removed version enforcement in
pip_install(). This changed behavior allows for custom version constraints to be specified in Meerschaum plugins. -
Backported
UPDATE FROMquery for older versions of SQLite. The current mutable data logic uses anUPDATE FROMquery, but this syntax is only present in versions of SQLite greater than 3.33.0 (released 2020-08-14). This releases splits the same logic intoDELETEandINSERTqueries for older versions of SQLite. -
Fixed missing suggestions for shell-only commands. Completions for commands like
instanceare now suggested. -
Fixed an issue with killing background jobs. The signals were not being sent correctly, so this release includes better job process management.
1.1.x Releases¶
Read release notes
The 1.1.x series brought a lot of great new features, notably connector URI parsing (e.g. MRSM_SQL_<LABEL>), parsing underscores as spaces in actions, and rewriting the Docker image to run at as a normal user.
v1.1.9 – v1.1.10¶
- Fixed plugins virtual environments. A typo in v1.1.8 temporarily broke plugins, and this patch fixes that change.
- Fixed Meerschaum on Windows.
A change in a previous release allowed for dist-packages for the root user (not advised but supported). The check for root (
os.geteuid()) does not exist on Windows, so this patch accounts for that behavior. - Tweaked screen clearing on Windows.
Meerschaum now always uses
clearorclson Windows instead of ANSI escape sequences.
v1.1.5 – v1.1.8¶
- Fixed
MRSM_PATCHbehavior. In the docker image,MRSM_PATCHis used to overwritehostforsql:main. This patch restores that behavior (with a performance boost). - Fixed virtual environment verification. This patch prevents circular symlinks.
- Fixed
manually_import_module(). Previous refactoring efforts had brokenmanually_import_module(). - Refactoring While trying to implement multi-thread configuration patching (discarded for the time being), much of the configuration system was cleaned up.
v1.1.1 – v1.1.4¶
Bugfixes
The first four versions following the initial v1.1.0 release addressed breaking changes and edge cases. Below are some notable issues resolved:
- Fixed broken Docker images. Changes to the environment and package systems broke functionality of the Docker images. For example, v1.1.0 switched to a stricter package management policy, but this new policy broke the mechanism behind the Docker images (user-level vs venv-level packages).
- Verify virtual environments for multiple Python versions.
When a virtual environment is first activated, Meerschaum now verifies that the
pythonsymlinks point to the correct versions. This is necessary due to a quirk invenvandvirtualenvwhere activating an existing environment with a different Python version overwrites the existingpythonsymlink. It also ensures that the symlinks specify the correct version number, e.g.python3.10. This bevavior is now automatic but may be invoked withmrsm verify venvs. - Fixed inconsistent environment behavior with
gunicorn. This one was tricky to troubleshoot. Due to the migration to the user-level Docker image, a subtle bug surfaced where the environment variables forgunicornwere incorrectly serialized. - Fixed slow-performing edge cases in
determine_version(). Inconsistencies in naming conventions in some packages likepygmentsled to failures to quickly determine the version. - Fixed Web API actions.
In v1.1.0, the default virtual environment was pinned to
mrsm, and this broke a function which relied on the old inferred default value ofNone. Always remember: explicit is better than implicit. - Fixed
start jobfor existing jobs. The same naming change brokedaemon_action(). Explcit code is important, folks!
v1.1.0¶
What's New
- Underscores in actions may now be parsed as spaces. This took way more work than expected, but anyway, custom actions with underscores in the function names are now treated as spaces! Consider the following:
The above action may now be executed as foo bar or foo_bar:
- Create a
SQLConnectororAPIConnectordirectly from a URI. If you already have a connection string, you can skip providing credentials and build a connector directly from the URI. If you omit alabel, then the lowercase form of'<username>@<host>/<database>'is used:
from meerschaum.connectors import SQLConnector
uri = 'postgresql://user:pass@localhost:5432/db'
conn = SQLConnector(uri=uri)
print(conn)
# sql:user@localhost/db
conn = SQLConnector('foo', uri=uri)
print(conn)
# sql:foo
conn = SQLConnector.from_uri(uri)
print(conn)
# sql:user@localhost/db
The APIConnector may also be built from a URI:
from meerschaum.connectors import APIConnector
uri = 'http://user:pass@localhost:8000'
conn = APIConnector(uri=uri)
print(conn)
# api:username@localhost
conn = APIConnector('bar', uri=uri)
print(conn)
# api:bar
conn = APIConnector.from_uri(uri)
print(conn)
# api:user@localhost
- Define temporary connectors from URIs in environment variables.
If you set environment variables with the format
MRSM_SQL_<LABEL>to valid URIs, new connectors will be available under the keyssql:<label>, where<label>is the lowercase form of<LABEL>:
You can set as many connectors as you like, and they're treated the same as connectors registered in your permanent configuration.
### The following environment variable was already exported:
### MRSM_SQL_FOO=sqlite://///path/to/sqlite.db
import meerschaum as mrsm
conn = mrsm.get_connector('sql', 'foo')
print(conn.database)
# /path/to/sqlite.db
Bugfixes
- Resolved issues with conflicting virtual and base environments.
- Only reinstall a package available at the user-level if its version doesn't match. This was a subtle bug, but now packages are handled strictly in virtual environments except when an appropriate version is available. This may slow down performance, but the change is necessary to ensure a consistent environment.
Potentially Breaking Changes
- The database file path for SQLite and DuckDB is now required.
When creating a
SQLConnectorwith the flavorssqliteorduckdb, the attributedatabase(a file path or:memory:) is now required. - Removed
--configand--root-dir. These flags were added very early on but have always caused issues. Instead, please use the environment variablesMRSM_CONFIGorMRSM_PATCHfor modifying the runtime configuration, and useMRSM_ROOT_DIRto specify a file path to the root Meerschaum directory. - Virtual environments must be
Nonefor standard library packages. When importing a built-in module withattempt_import(), specifyvenv=Noneto avoid attempting installation. - The Docker image now runs as
meerschauminstead ofroot. For improved security, the docker image now runs at a lower privilege.
1.0.x Releases¶
Read release notes
The v1.0.0 release was big news. A ton of features, bugfixes, and perfomance improvements were introduced: for example, v1.0.0 brought support for mutable pipes and data type enforcement. Later releases in the v1.0.x series included --schedule, the Venv context manager, and a whole lot of environment bugfixes.
v1.0.6¶
- Plugins may now have
requirements.txt. If a plugin contains a file namedrequirements.txt, the file will be parsed alongside the packages specified in therequiredlist. - Added the module
meerschaum.utils.venv. Functions related to virtual environment management have been migrated frommeerschaum.utils.packagestomeerschaum.utils.venv. - Added the
Venvclass. You can now manage your virtual environments with theVenvcontext manager:
You can also activate the environments for a Plugin:
from meerschaum.utils.venv import Venv
from meerschaum.plugins import Plugin
with Venv(Plugin('noaa')):
import requests
- Removed
--isolatedfrompip_install. Virtual environments will now respect environment variables and your globalpipconfiguration (~/.pip/pip.conf). - Fixed issues for Python 3.7
v1.0.3 – v1.0.5¶
- Fixed environment bugs.
This patch resolves issues with the environment variables
MRSM_ROOT_DIR,MRSM_CONFIG, andMRSM_PATCHas well as the configuration directoriespatch_configandpermanent_patch_config. - Fixed package management system.
Meerschaum better handles package metadata, resolving some annoying issues. See
meerschaum.utils.packages.get_module_path()for an example of the improved virtual environment management system. Also,wheelis automatically installed when new packages are installed into new virtual environments. - Set the default venv to
'mrsm'. In all functions declared inmeerschaum.utils.packages, the default value ofvenvis always'mrsm'. UseNonefor thevenvto use the user's site packages. - Updated dependencies.
- Added
python-dotenvas a dependency. - Fixed a catalog issue with
duckdb. - Updated the testing suite.
- More refactoring. Code needs to be beautiful!
v1.0.2¶
- Allow
idcolumn to be omitted. When generating theUPDATEquery, theidcolumn may now be omitted (NOTE: the datetime column will be assumed to be the primary key in this scenario). - Added
--schedule(-sor--cron). The--scheduleflag (-s) now lets you schedule any command to be executed regulary, not unlike crontab. This can come in handy with--daemon(-d), e.g.:
Here is more information on the scheduling syntax.
- Fixed an issue with SQLite. An issue where the value columns not loading in SQLite has been addressed.
v1.0.1¶
- Added
citusas an official database flavor. Citus is a distributed database built on PostgreSQL. When anidcolumn is provided, Meerschaum will callcreate_distributed_table()on the pipe's ID index. Citus has also been added to the official test suite. - Changed
enddatetimes to be exclusive. Theendparameter now generates<instead of<=. This shouldn't be a major breaking change but is important to be aware of. - Bumped
richto v12.4.4.
v1.0.0: Mutable at Last¶
What's New
-
Inserts and Updates An additional layer of processing separates new rows from updated rows. Meerschaum uses your
datetimeandidcolumns (if you specified anidcolumn) to determine which rows have changed. Therefore a primary key is not required, as long as thedatetimecolumn is unique or thedatetimeandidcolumns together emulate a composite primary key.Meerschaum will insert new rows as before as well as creating a temporary table (same name as the pipe's target but with a leading underscore). The syncing engine then issues the appropriate
MERGEorUPDATEquery to update all of the rows in a batch.For example, the following lines of code will result in a table with only 1 row:
>>> import meerschaum as mrsm >>> pipe = mrsm.Pipe('foo', 'bar', columns={'datetime': 'dt', 'id': 'id'}) >>> >>> ### Insert the first row. >>> pipe.sync([{'dt': '2022-06-26', 'id': 1, 'value': 10}]) >>> >>> ### Duplicate row, no change. >>> pipe.sync([{'dt': '2022-06-26', 'id': 1, 'value': 10}]) >>> >>> ### Update the value columns of the first row. >>> pipe.sync([{'dt': '2022-06-26', 'id': 1, 'value': 100}]) -
Data Type Enforcement. Incoming DataFrames will be cast to the pipe's existing data types, and if you want total control, you can manually specify the Pandas data types for as many columns as you like under the
dtypeskey ofPipe.parameters, e.g.: - Allow for
NULLinINTcolumns. Before pandas v1.3.0, including a null value in an int column would cast it to a float. Nowpd.NAhas been added and is leveraged in Meerschaum's data type inference system. - Plugins respect
.gitignoreWhen publishing a plugin that is contained in a git repository, Meerschaum will parse your.gitignorefile to determine which files to omit. - Private API Mode.
Require authentication on all API endpoints with
start api --private. - No Authentication API Mode.
Adding
--no-authwill disable all authentication on all API endpoints, including the web console.
Bugfixes
-
Plugin packaging A breaking bug in the process of packaging and publishing Meerschaum plugins has been patched.
-
Correct object names in Oracle SQL. Oracle has finally been brought up to speed with other flavors.
- Multi-module plugins fix. A small but important fix for multi-module plugins has been applied for their virtual environments.
- Improved virtual environment handling for Debian systems.
If
venvis not available, Meerschaum now better handles falling back tovirtualenv. - Allow for syncing lists of dicts.
In addition to syncing a dict of lists,
Pipe.sync()now supports a list of dicts. - Allow for
beginto equalNoneforPipe.fetch(). The behavior of determiningbeginfromPipe.get_sync_time()only takes place whenbeginis omitted, not when it isNone. Nowbegin=Nonewill not add a lower bound to the query.