Compare commits

..

No commits in common. "master" and "v0.1.1" have entirely different histories.

12 changed files with 158 additions and 218 deletions

3
.gitignore vendored
View file

@ -1,4 +1 @@
*~
*.pyc
dist/
rattail_mailchimp.egg-info/ rattail_mailchimp.egg-info/

View file

@ -5,54 +5,6 @@ All notable changes to rattail-mailchimp will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.3.3 (2024-07-05)
### Fix
- define `host_key` for MailChimp -> Rattail import
## v0.3.2 (2024-07-01)
### Fix
- remove legacy command definitions
## v0.3.1 (2024-06-14)
### Fix
- fallback to `importlib_metadata` on older python
## v0.3.0 (2024-06-10)
### Feat
- switch from setup.cfg to pyproject.toml + hatchling
## [0.2.1] - 2024-06-04
### Changed
- Setup default handler for Mailchimp -> Rattail import.
## [0.2.0] - 2024-06-03
### Changed
- Migrate all commands to use `typer`.
## [0.1.5] - 2023-11-30
### Changed
- Update subcommand entry point group names, per wuttjamaican.
## [0.1.4] - 2023-06-01
### Changed
- Replace `setup.py` contents with `setup.cfg`.
## [0.1.3] - 2023-05-13
### Changed
- Avoid deprecated import for `OrderedDict`.
## [0.1.2] - 2023-02-21
### Changed
- Tweak ORM relationship backrefs per SA 2.0 warnings.
## [0.1.1] - 2022-08-06 ## [0.1.1] - 2022-08-06
### Changed ### Changed
- Register email profiles provided by this pkg. - Register email profiles provided by this pkg.

View file

@ -1,11 +0,0 @@
# rattail_mailchimp
Rattail is a retail software framework, released under the GNU General
Public License.
This package contains software interfaces for the
[MailChimp](https://mailchimp.com/) system.
Please see the [Rattail Project](https://rattailproject.org/) for more
information.

14
README.rst Normal file
View file

@ -0,0 +1,14 @@
rattail_mailchimp
=================
Rattail is a retail software framework, released under the GNU General
Public License.
This package contains software interfaces for the `MailChimp`_ system.
.. _`MailChimp`: https://mailchimp.com/
Please see the `Rattail Project`_ for more information.
.. _`Rattail Project`: https://rattailproject.org/

View file

@ -1,54 +0,0 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "rattail-mailchimp"
version = "0.3.3"
description = "Rattail Software Interfaces for MailChimp"
readme = "README.md"
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
license = {text = "GNU GPL v3+"}
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Environment :: Web Environment",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Topic :: Office/Business",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"mailchimp3",
"rattail",
]
[project.entry-points."rattail.config.extensions"]
rattail_mailchimp = "rattail_mailchimp.config:MailchimpConfigExtension"
[project.entry-points."rattail.typer_imports"]
rattail_mailchimp = "rattail_mailchimp.commands"
[project.entry-points."rattail.emails"]
rattail_mailchimp = "rattail_mailchimp.emails"
[project.urls]
Homepage = "https://rattailproject.org"
Repository = "https://kallithea.rattailproject.org/rattail-project/rattail-mailchimp"
Changelog = "https://kallithea.rattailproject.org/rattail-project/rattail-mailchimp/files/master/CHANGELOG.md"
[tool.commitizen]
version_provider = "pep621"
tag_format = "v$version"
update_changelog_on_bump = true

View file

@ -1,9 +1,3 @@
# -*- coding: utf-8; -*- # -*- coding: utf-8; -*-
try: __version__ = '0.1.1'
from importlib.metadata import version
except ImportError:
from importlib_metadata import version
__version__ = version('rattail-mailchimp')

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2024 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -24,25 +24,23 @@
Rattail Commands for MailChimp integration Rattail Commands for MailChimp integration
""" """
import typer from rattail import commands
from rattail.util import load_object
from rattail.commands import rattail_typer
from rattail.commands.typer import importer_command, typer_get_runas_user
from rattail.commands.importing import ImportCommandHandler
@rattail_typer.command() class ImportMailChimp(commands.ImportSubcommand):
@importer_command
def import_mailchimp(
ctx: typer.Context,
**kwargs
):
""" """
Import data to Rattail, from MailChimp API Import data to Rattail, from MailChimp API
""" """
config = ctx.parent.rattail_config name = 'import-mailchimp'
progress = ctx.parent.rattail_progress description = __doc__.strip()
handler = ImportCommandHandler( default_handler_spec = 'rattail_mailchimp.importing.mailchimp:FromMailChimpToRattail'
config, import_handler_key='to_rattail.from_mailchimp.import')
kwargs['user'] = typer_get_runas_user(ctx) def get_handler_factory(self, **kwargs):
handler.run(kwargs, progress=progress) if self.config:
spec = self.config.get('rattail.importing', 'mailchimp.handler',
default=self.default_handler_spec)
else:
# just use default, for sake of cmd line help
spec = self.default_handler_spec
return load_object(spec)

View file

@ -1,42 +0,0 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Config extensions for rattail-mailchimp
"""
from wuttjamaican.conf import WuttaConfigExtension
class MailchimpConfigExtension(WuttaConfigExtension):
"""
Config extension for rattail-mailchimp
"""
key = 'rattail_mailchimp'
def configure(self, config):
# rattail import-mailchimp
config.setdefault('rattail.importing', 'to_rattail.from_mailchimp.import.default_handler',
'rattail_mailchimp.importing.mailchimp:FromMailChimpToRattail')
config.setdefault('rattail.importing', 'to_rattail.from_mailchimp.import.default_cmd',
'rattail import-mailchimp')

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2023 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -45,11 +45,6 @@ class MailChimpList(model.Base):
date_created = sa.Column(sa.DateTime(), nullable=True) date_created = sa.Column(sa.DateTime(), nullable=True)
members = orm.relationship('MailChimpListMember',
back_populates='list',
# nb. this is to satisfy SA 2.0
cascade_backrefs=False)
def __str__(self): def __str__(self):
return self.name or "" return self.name or ""
@ -67,8 +62,7 @@ class MailChimpListMember(model.Base):
uuid = model.uuid_column() uuid = model.uuid_column()
list_uuid = sa.Column(sa.String(length=32), nullable=False) list_uuid = sa.Column(sa.String(length=32), nullable=False)
list = orm.relationship(MailChimpList, list = orm.relationship(MailChimpList, backref='members')
back_populates='members')
id = sa.Column(sa.String(length=32), nullable=True) id = sa.Column(sa.String(length=32), nullable=True)

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2024 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -25,11 +25,12 @@ MailChimp -> Rattail "cache" data import
""" """
import datetime import datetime
from collections import OrderedDict
from mailchimp3 import MailChimp from mailchimp3 import MailChimp
from rattail import importing from rattail import importing
from rattail.util import OrderedDict
from rattail.time import localtime, make_utc
from rattail_mailchimp import importing as mailchimp_importing from rattail_mailchimp import importing as mailchimp_importing
@ -37,9 +38,7 @@ class FromMailChimpToRattail(importing.ToRattailHandler):
""" """
Handler for MailChimp -> Rattail cache import Handler for MailChimp -> Rattail cache import
""" """
host_key = 'mailchimp'
host_title = "MailChimp" host_title = "MailChimp"
generic_host_title = "MailChimp"
def get_importers(self): def get_importers(self):
importers = OrderedDict() importers = OrderedDict()
@ -54,7 +53,7 @@ class FromMailChimp(importing.Importer):
""" """
def setup(self): def setup(self):
super().setup() super(FromMailChimp, self).setup()
self.api_key = self.config.require('mailchimp', 'api_key') self.api_key = self.config.require('mailchimp', 'api_key')
self.mailchimp = MailChimp(self.api_key) self.mailchimp = MailChimp(self.api_key)
@ -66,10 +65,10 @@ class FromMailChimp(importing.Importer):
# issue..since we clearly have a UTC value # issue..since we clearly have a UTC value
value = value[:-6] value = value[:-6]
dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S') dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S')
dt = self.app.localtime(dt, from_utc=True) dt = localtime(self.config, dt, from_utc=True)
else: else:
dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S%z') dt = datetime.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S%z')
dt = self.app.localtime(dt) dt = localtime(self.config, dt)
return dt return dt
@ -96,7 +95,7 @@ class MailChimpListImporter(FromMailChimp, mailchimp_importing.model.MailChimpLi
return { return {
'id': mclist['id'], 'id': mclist['id'],
'name': mclist['name'], 'name': mclist['name'],
'date_created': self.app.make_utc(date_created), 'date_created': make_utc(date_created),
} }
@ -131,20 +130,10 @@ class MailChimpListMemberImporter(FromMailChimp, mailchimp_importing.model.MailC
def get_all_members(self, list_id): def get_all_members(self, list_id):
members = [] members = []
# cf. https://mailchimp.com/developer/marketing/api/list-members/list-members-info/
result = self.mailchimp.lists.members.all(list_id, get_all=True, result = self.mailchimp.lists.members.all(list_id, get_all=True,
# TODO: maybe should try this instead of # TODO: maybe should try this instead of
# the default which seems to be 500 # the default which seems to be 500
# count=1000 # count=1000
# TODO: this testing chunk left here for
# reference; it can be handy to filter
# results etc. for test runs
# count=500,
# # since_last_changed=datetime.date(2023, 1, 1),
# sort_field='last_changed',
# sort_dir='DESC',
) )
members.extend(result['members']) members.extend(result['members'])
return members return members
@ -161,6 +150,6 @@ class MailChimpListMemberImporter(FromMailChimp, mailchimp_importing.model.MailC
'status': member['status'], 'status': member['status'],
# TODO: this API endpoint does not appear to include this field? # TODO: this API endpoint does not appear to include this field?
# 'unsubscribe_reason': member.get('unsubscribe_reason'), # 'unsubscribe_reason': member.get('unsubscribe_reason'),
'last_changed': self.app.make_utc(last_changed), 'last_changed': make_utc(last_changed),
'source': member['source'], 'source': member['source'],
} }

107
setup.py Normal file
View file

@ -0,0 +1,107 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail is free software: you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'rattail_mailchimp', '_version.py')).read())
README = open(os.path.join(here, 'README.rst')).read()
requires = [
#
# Version numbers within comments below have specific meanings.
# Basically the 'low' value is a "soft low," and 'high' a "soft high."
# In other words:
#
# If either a 'low' or 'high' value exists, the primary point to be
# made about the value is that it represents the most current (stable)
# version available for the package (assuming typical public access
# methods) whenever this project was started and/or documented.
# Therefore:
#
# If a 'low' version is present, you should know that attempts to use
# versions of the package significantly older than the 'low' version
# may not yield happy results. (A "hard" high limit may or may not be
# indicated by a true version requirement.)
#
# Similarly, if a 'high' version is present, and especially if this
# project has laid dormant for a while, you may need to refactor a bit
# when attempting to support a more recent version of the package. (A
# "hard" low limit should be indicated by a true version requirement
# when a 'high' version is present.)
#
# In any case, developers and other users are encouraged to play
# outside the lines with regard to these soft limits. If bugs are
# encountered then they should be filed as such.
#
# package # low high
'mailchimp3', # 3.0.14
'rattail', # 0.9.214
]
setup(
name = "rattail-mailchimp",
version = __version__,
author = "Lance Edgar",
author_email = "lance@edbob.org",
url = "https://rattailproject.org/",
license = "GNU GPL v3",
description = "Rattail Software Interfaces for MailChimp",
long_description = README,
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Console',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Topic :: Office/Business',
'Topic :: Software Development :: Libraries :: Python Modules',
],
install_requires = requires,
packages = find_packages(),
include_package_data = True,
zip_safe = False,
entry_points = {
'rattail.commands': [
'import-mailchimp = rattail_mailchimp.commands:ImportMailChimp',
],
'rattail.emails': [
'rattail_mailchimp = rattail_mailchimp.emails',
],
},
)

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2024 Lance Edgar # Copyright © 2010-2022 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -30,15 +30,17 @@ import shutil
from invoke import task from invoke import task
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'rattail_mailchimp', '_version.py')).read())
@task @task
def release(c): def release(ctx):
""" """
Release a new version of 'rattail-mailchimp'. Release a new version of 'rattail-mailchimp'.
""" """
if os.path.exists('dist'): shutil.rmtree('rattail_mailchimp.egg-info')
shutil.rmtree('dist') ctx.run('python -m build --sdist')
if os.path.exists('rattail_mailchimp.egg-info'):
shutil.rmtree('rattail_mailchimp.egg-info')
c.run('python -m build --sdist')
c.run('twine upload dist/*') filename = 'rattail-mailchimp-{}.tar.gz'.format(__version__)
ctx.run('twine upload dist/{}'.format(filename))