Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Black support for the Python codebase #4297

Merged
merged 3 commits into from
Dec 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Python Code Formatting (Black)

on:
push:
branches:
- master

jobs:
format:
runs-on: ubuntu-latest

container:
image: python:3.7.4-alpine

steps:
- uses: actions/checkout@v1
- name: Install Black
run: apk add gcc musl-dev && pip install black
- name: Run Black
run: black redash tests migrations/versions
- name: Commit formatted code
uses: EndBug/[email protected]
with:
author_name: Black
author_email: [email protected]
message: "Autoformatted Python code with Black"
path: "."
pattern: "*.py"
force: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14 changes: 7 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,18 @@ When creating a new bug report, please make sure to:

If you would like to suggest an enhancement or ask for a new feature:

- Please check [the roadmap](https://trello.com/b/b2LUHU7A/redash-roadmap) for existing Trello card for what you want to suggest/ask. If there is, feel free to upvote it to signal interest or add your comments.
- If there is no existing card, open a thread in [the forum](https://discuss.redash.io/c/feature-requests) to start a discussion about what you want to suggest. Try to provide as much details and context as possible and include information about *the problem you want to solve* rather only *your proposed solution*.
- Please check [the forum](https://discuss.redash.io/c/feature-requests/5) for existing threads about what you want to suggest/ask. If there is, feel free to upvote it to signal interest or add your comments.
- If there is no open thread, you're welcome to start one to have a discussion about what you want to suggest. Try to provide as much details and context as possible and include information about *the problem you want to solve* rather only *your proposed solution*.

### Pull Requests

- **Code contributions are welcomed**. For big changes or significant features, it's usually better to reach out first and discuss what you want to implement and how (we recommend reading: [Pull Request First](https://medium.com/practical-blend/pull-request-first-f6bb667a9b6#.ozlqxvj36)). This to make sure that what you want to implement is aligned with our goals for the project and that no one else is already working on it.
- Include screenshots and animated GIFs in your pull request whenever possible.
- Please add [documentation](#documentation) for new features or changes in functionality along with the code.
- Please follow existing code style:
- Python: we use PEP8 for Python.
- Javascript: we use Airbnb's style guides for [JavaScript](https://github.com/airbnb/javascript#naming-conventions) and [React](https://github.com/airbnb/javascript/blob/master/react) (currently we don't follow Airbnb's convention for naming files, but we're gradually fixing this). To make it automatic and easy, we recommend using [Prettier](https://github.com/prettier/prettier).

- Python: we use [Black](https://github.com/psf/black) to auto format the code.
- Javascript: we use [Prettier](https://github.com/prettier/prettier) to auto-format the code.
### Documentation

The project's documentation can be found at [https://redash.io/help/](https://redash.io/help/). The [documentation sources](https://github.com/getredash/website/tree/master/src/pages/kb) are hosted on GitHub. To contribute edits / new pages, you can use GitHub's interface. Click the "Edit on GitHub" link on the documentation page to quickly open the edit interface.
Expand All @@ -66,9 +66,9 @@ The project's documentation can be found at [https://redash.io/help/](https://re

### Release Method

We publish a stable release every ~2 months, although the goal is to get to a stable release every month. You can see the change log on [GitHub releases page](https://github.com/getredash/redash/releases).
We publish a stable release every ~3-4 months, although the goal is to get to a stable release every month.

Every build of the master branch updates the latest *RC release*. These releases are usually stable, but might contain regressions and therefore recommended for "advanced users" only.
Every build of the master branch updates the *redash/redash:preview* Docker Image. These releases are usually stable, but might contain regressions and therefore recommended for "advanced users" only.

When we release a new stable release, we also update the *latest* Docker image tag, the EC2 AMIs and GCE images.

Expand Down
8 changes: 4 additions & 4 deletions migrations/versions/0f740a081d20_inline_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@


# revision identifiers, used by Alembic.
revision = '0f740a081d20'
down_revision = 'a92d92aa678e'
revision = "0f740a081d20"
down_revision = "a92d92aa678e"
branch_labels = None
depends_on = None


def upgrade():
tags_regex = re.compile('^([\w\s]+):|#([\w-]+)', re.I | re.U)
tags_regex = re.compile("^([\w\s]+):|#([\w-]+)", re.I | re.U)
connection = op.get_bind()

dashboards = connection.execute("SELECT id, name FROM dashboards")

update_query = text("UPDATE dashboards SET tags = :tags WHERE id = :id")

for dashboard in dashboards:
tags = compact(flatten(tags_regex.findall(dashboard[1])))
if tags:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,15 @@


# revision identifiers, used by Alembic.
revision = '1daa601d3ae5'
down_revision = '969126bd800f'
revision = "1daa601d3ae5"
down_revision = "969126bd800f"
branch_labels = None
depends_on = None


def upgrade():
op.add_column(
'users',
sa.Column('disabled_at', sa.DateTime(True), nullable=True)
)
op.add_column("users", sa.Column("disabled_at", sa.DateTime(True), nullable=True))


def downgrade():
op.drop_column('users', 'disabled_at')
op.drop_column("users", "disabled_at")
24 changes: 14 additions & 10 deletions migrations/versions/5ec5c84ba61e_.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,28 @@


# revision identifiers, used by Alembic.
revision = '5ec5c84ba61e'
down_revision = '7671dca4e604'
revision = "5ec5c84ba61e"
down_revision = "7671dca4e604"
branch_labels = None
depends_on = None


def upgrade():
conn = op.get_bind()
op.add_column('queries', sa.Column('search_vector', su.TSVectorType()))
op.create_index('ix_queries_search_vector', 'queries', ['search_vector'],
unique=False, postgresql_using='gin')
ss.sync_trigger(conn, 'queries', 'search_vector',
['name', 'description', 'query'])
op.add_column("queries", sa.Column("search_vector", su.TSVectorType()))
op.create_index(
"ix_queries_search_vector",
"queries",
["search_vector"],
unique=False,
postgresql_using="gin",
)
ss.sync_trigger(conn, "queries", "search_vector", ["name", "description", "query"])


def downgrade():
conn = op.get_bind()

ss.drop_trigger(conn, 'queries', 'search_vector')
op.drop_index('ix_queries_search_vector', table_name='queries')
op.drop_column('queries', 'search_vector')
ss.drop_trigger(conn, "queries", "search_vector")
op.drop_index("ix_queries_search_vector", table_name="queries")
op.drop_column("queries", "search_vector")
115 changes: 66 additions & 49 deletions migrations/versions/640888ce445d_.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,93 +15,110 @@


# revision identifiers, used by Alembic.
revision = '640888ce445d'
down_revision = '71477dadd6ef'
revision = "640888ce445d"
down_revision = "71477dadd6ef"
branch_labels = None
depends_on = None


def upgrade():
# Copy "schedule" column into "old_schedule" column
op.add_column('queries', sa.Column('old_schedule', sa.String(length=10), nullable=True))
op.add_column(
"queries", sa.Column("old_schedule", sa.String(length=10), nullable=True)
)

queries = table(
'queries',
sa.Column('schedule', sa.String(length=10)),
sa.Column('old_schedule', sa.String(length=10)))
"queries",
sa.Column("schedule", sa.String(length=10)),
sa.Column("old_schedule", sa.String(length=10)),
)

op.execute(
queries
.update()
.values({'old_schedule': queries.c.schedule}))
op.execute(queries.update().values({"old_schedule": queries.c.schedule}))

# Recreate "schedule" column as a dict type
op.drop_column('queries', 'schedule')
op.add_column('queries', sa.Column('schedule', MutableDict.as_mutable(PseudoJSON), nullable=False, server_default=json.dumps({})))
op.drop_column("queries", "schedule")
op.add_column(
"queries",
sa.Column(
"schedule",
MutableDict.as_mutable(PseudoJSON),
nullable=False,
server_default=json.dumps({}),
),
)

# Move over values from old_schedule
queries = table(
'queries',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('schedule', MutableDict.as_mutable(PseudoJSON)),
sa.Column('old_schedule', sa.String(length=10)))
"queries",
sa.Column("id", sa.Integer, primary_key=True),
sa.Column("schedule", MutableDict.as_mutable(PseudoJSON)),
sa.Column("old_schedule", sa.String(length=10)),
)

conn = op.get_bind()
for query in conn.execute(queries.select()):
schedule_json = {
'interval': None,
'until': None,
'day_of_week': None,
'time': None
"interval": None,
"until": None,
"day_of_week": None,
"time": None,
}

if query.old_schedule is not None:
if ":" in query.old_schedule:
schedule_json['interval'] = 86400
schedule_json['time'] = query.old_schedule
schedule_json["interval"] = 86400
schedule_json["time"] = query.old_schedule
else:
schedule_json['interval'] = query.old_schedule
schedule_json["interval"] = query.old_schedule

conn.execute(
queries
.update()
.where(queries.c.id == query.id)
.values(schedule=MutableDict(schedule_json)))
queries.update()
.where(queries.c.id == query.id)
.values(schedule=MutableDict(schedule_json))
)

op.drop_column("queries", "old_schedule")

op.drop_column('queries', 'old_schedule')

def downgrade():
op.add_column('queries', sa.Column('old_schedule', MutableDict.as_mutable(PseudoJSON), nullable=False, server_default=json.dumps({})))
op.add_column(
"queries",
sa.Column(
"old_schedule",
MutableDict.as_mutable(PseudoJSON),
nullable=False,
server_default=json.dumps({}),
),
)

queries = table(
'queries',
sa.Column('schedule', MutableDict.as_mutable(PseudoJSON)),
sa.Column('old_schedule', MutableDict.as_mutable(PseudoJSON)))
"queries",
sa.Column("schedule", MutableDict.as_mutable(PseudoJSON)),
sa.Column("old_schedule", MutableDict.as_mutable(PseudoJSON)),
)

op.execute(
queries
.update()
.values({'old_schedule': queries.c.schedule}))
op.execute(queries.update().values({"old_schedule": queries.c.schedule}))

op.drop_column('queries', 'schedule')
op.add_column('queries', sa.Column('schedule', sa.String(length=10), nullable=True))
op.drop_column("queries", "schedule")
op.add_column("queries", sa.Column("schedule", sa.String(length=10), nullable=True))

queries = table(
'queries',
sa.Column('id', sa.Integer, primary_key=True),
sa.Column('schedule', sa.String(length=10)),
sa.Column('old_schedule', MutableDict.as_mutable(PseudoJSON)))
"queries",
sa.Column("id", sa.Integer, primary_key=True),
sa.Column("schedule", sa.String(length=10)),
sa.Column("old_schedule", MutableDict.as_mutable(PseudoJSON)),
)

conn = op.get_bind()
for query in conn.execute(queries.select()):
scheduleValue = query.old_schedule['interval']
scheduleValue = query.old_schedule["interval"]
if scheduleValue <= 86400:
scheduleValue = query.old_schedule['time']
scheduleValue = query.old_schedule["time"]

conn.execute(
queries
.update()
.where(queries.c.id == query.id)
.values(schedule=scheduleValue))
queries.update()
.where(queries.c.id == query.id)
.values(schedule=scheduleValue)
)

op.drop_column('queries', 'old_schedule')
op.drop_column("queries", "old_schedule")
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,36 @@
# revision identifiers, used by Alembic.
from sqlalchemy.exc import ProgrammingError

revision = '65fc9ede4746'
revision = "65fc9ede4746"
down_revision = None
branch_labels = None
depends_on = None


def upgrade():
try:
op.add_column('queries', sa.Column('is_draft', sa.Boolean, default=True, index=True))
op.add_column('dashboards', sa.Column('is_draft', sa.Boolean, default=True, index=True))
op.add_column(
"queries", sa.Column("is_draft", sa.Boolean, default=True, index=True)
)
op.add_column(
"dashboards", sa.Column("is_draft", sa.Boolean, default=True, index=True)
)
op.execute("UPDATE queries SET is_draft = (name = 'New Query')")
op.execute("UPDATE dashboards SET is_draft = false")
except ProgrammingError as e:
# The columns might exist if you ran the old migrations.
if 'column "is_draft" of relation "queries" already exists' in str(e):
print("Can't run this migration as you already have is_draft columns, please run:")
print("./manage.py db stamp {} # you might need to alter the command to match your environment.".format(revision))
print(
"Can't run this migration as you already have is_draft columns, please run:"
)
print(
"./manage.py db stamp {} # you might need to alter the command to match your environment.".format(
revision
)
)
exit()


def downgrade():
op.drop_column('queries', 'is_draft')
op.drop_column('dashboards', 'is_draft')
op.drop_column("queries", "is_draft")
op.drop_column("dashboards", "is_draft")
Loading