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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign initialization of HasProps instances #13872

Open
wants to merge 1 commit into
base: branch-3.5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
36 changes: 31 additions & 5 deletions bokehjs/src/lib/core/has_props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,6 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa
assert(keys(attrs).length == 1, "'id' cannot be used together with property initializers")
} else {
this.initialize_props(attrs)
this.finalize()
this.connect_signals()
}
}

Expand All @@ -359,21 +357,35 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa
}
}

private _initialized: boolean = false
initialize(): void {
assert(!this._initialized)
this._initialized = true
}

/*
finalize(): void {
this.initialize()
}
*/
//instance.finalize()
//instance.assert_initialized()

initialize(): void {}

/*
assert_initialized(): void {
for (const prop of this) {
if (prop.syncable && !prop.readonly) {
prop.get_value()
}
}
}
*/

private _signals_connected: boolean = false
connect_signals(): void {
assert(!this._signals_connected)
this._signals_connected = true

for (const prop of this) {
if (!(prop instanceof p.VectorSpec || prop instanceof p.ScalarSpec)) {
continue
Expand All @@ -394,6 +406,7 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa

disconnect_signals(): void {
Signal.disconnect_receiver(this)
this._signals_connected = false
}

destroy(): void {
Expand Down Expand Up @@ -559,6 +572,9 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa
HasProps._value_record_references(value, refs, {recursive})
}
}
for (const ref of value._references()) {
HasProps._value_record_references(ref, refs, {recursive})
}
}
}
} else if (isIterable(value)) {
Expand All @@ -572,6 +588,8 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa
}
}

protected *_references(): Iterable<HasProps> {}

static references(value: unknown, options: {recursive: boolean}): Set<HasProps> {
const refs = new Set<HasProps>()
HasProps._value_record_references(value, refs, options)
Expand All @@ -591,16 +609,24 @@ export abstract class HasProps extends Signalable() implements Equatable, Printa
if (this.document == doc) {
return
} else {
throw new Error("models must be owned by only a single document")
throw new Error(`${this} must be owned by only a single document`)
}
}

this.document = doc
this._doc_attached()

if (!this._initialized) {
this.initialize()
}
if (!this._signals_connected) {
this.connect_signals()
}
}

detach_document(): void {
// This should only be called by the Document implementation to unset the document field
this.disconnect_signals()
this._doc_detached()
this.document = null
}
Expand Down
8 changes: 5 additions & 3 deletions bokehjs/src/lib/core/serialization/deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,7 @@ export class Deserializer {
})()

for (const instance of finalizable) {
this.finalize?.(instance)
instance.finalize()
instance.assert_initialized()
instance.initialize()
}

// `connect_signals` has to be executed last because it may rely on properties
Expand All @@ -83,6 +81,10 @@ export class Deserializer {
instance.connect_signals()
}

for (const instance of finalizable) {
this.finalize?.(instance)
}

return decoded
}

Expand Down
7 changes: 1 addition & 6 deletions bokehjs/src/lib/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface Model extends Model.Attrs {}
export class Model extends HasProps {
declare properties: Model.Props

private /*readonly*/ _js_callbacks: Map<string, (() => void)[]>
private readonly _js_callbacks: Map<string, (() => void)[]> = new Map()

override get is_syncable(): boolean {
return this.syncable
Expand All @@ -60,11 +60,6 @@ export class Model extends HasProps {
}))
}

override initialize(): void {
super.initialize()
this._js_callbacks = new Map()
}

override connect_signals(): void {
super.connect_signals()

Expand Down
7 changes: 1 addition & 6 deletions bokehjs/src/lib/models/annotations/legend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,17 +496,12 @@ export class Legend extends Annotation {
declare properties: Legend.Props
declare __view_type__: LegendView

item_change: Signal0<this>
readonly item_change = new Signal0(this, "item_change")

constructor(attrs?: Partial<Legend.Attrs>) {
super(attrs)
}

override initialize(): void {
super.initialize()
this.item_change = new Signal0(this, "item_change")
}

static {
this.prototype.default_view = LegendView

Expand Down
9 changes: 6 additions & 3 deletions bokehjs/src/lib/models/annotations/legend_item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface LegendItem extends LegendItem.Attrs {}
export class LegendItem extends Model {
declare properties: LegendItem.Props

legend: Legend | null
legend: Legend | null = null

constructor(attrs?: Partial<LegendItem.Attrs>) {
super(attrs)
Expand Down Expand Up @@ -70,8 +70,6 @@ export class LegendItem extends Model {

override initialize(): void {
super.initialize()
this.legend = null
this.connect(this.change, () => this.legend?.item_change.emit())

// Validate data_sources match
const data_source_validation = this._check_data_sources_on_renderers()
Expand All @@ -86,6 +84,11 @@ export class LegendItem extends Model {
}
}

override connect_signals(): void {
super.connect_signals()
this.connect(this.change, () => this.legend?.item_change.emit())
}

get_field_from_label_prop(): string | null {
const {label} = this
return isField(label) ? label.field : null
Expand Down
14 changes: 2 additions & 12 deletions bokehjs/src/lib/models/expressions/expression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ export abstract class Expression<T = Arrayable> extends Model {
super(attrs)
}

protected _result: Map<ColumnarDataSource, T>

override initialize(): void {
super.initialize()
this._result = new Map()
}
protected readonly _result: Map<ColumnarDataSource, T> = new Map()

protected abstract _v_compute(source: ColumnarDataSource): T

Expand Down Expand Up @@ -52,12 +47,7 @@ export abstract class ScalarExpression<T> extends Model {
super(attrs)
}

protected _result: Map<ColumnarDataSource, T>

override initialize(): void {
super.initialize()
this._result = new Map()
}
protected readonly _result: Map<ColumnarDataSource, T> = new Map()

protected abstract _compute(source: ColumnarDataSource): T

Expand Down
7 changes: 1 addition & 6 deletions bokehjs/src/lib/models/formatters/log_tick_formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@ export class LogTickFormatter extends TickFormatter {
}))
}

protected basic_formatter: BasicTickFormatter

override initialize(): void {
super.initialize()
this.basic_formatter = new BasicTickFormatter()
}
protected readonly basic_formatter = new BasicTickFormatter()

override format_graphics(ticks: number[], opts: {loc: number}): GraphicsBox[] {
if (ticks.length == 0) {
Expand Down
7 changes: 1 addition & 6 deletions bokehjs/src/lib/models/mappers/color_mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,12 @@ export interface ColorMapper extends ColorMapper.Attrs {}
export abstract class ColorMapper extends Mapper<Color> {
declare properties: ColorMapper.Props

metrics_change: Signal0<this>
readonly metrics_change = new Signal0(this, "metrics_change")

constructor(attrs?: Partial<ColorMapper.Attrs>) {
super(attrs)
}

override initialize(): void {
super.initialize()
this.metrics_change = new Signal0(this, "metrics_change")
}

static {
this.define<ColorMapper.Props>(({Color, List}) => ({
palette: [ List(Color) ],
Expand Down
11 changes: 2 additions & 9 deletions bokehjs/src/lib/models/sources/columnar_data_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export abstract class ColumnarDataSource extends DataSource {
return column as T[]
}

_select: Signal0<this>
inspect: Signal<[GlyphRenderer, {geometry: Geometry}], this>
readonly _select: Signal0<this> = new Signal0(this, "select")
readonly inspect: Signal<[GlyphRenderer, {geometry: Geometry}], this> = new Signal(this, "inspect")

readonly selection_manager = new SelectionManager(this)

Expand All @@ -69,13 +69,6 @@ export abstract class ColumnarDataSource extends DataSource {
}))
}

override initialize(): void {
super.initialize()

this._select = new Signal0(this, "select")
this.inspect = new Signal(this, "inspect")
}

get inferred_defaults(): Map<string, unknown> {
const defaults: Map<string, unknown> = new Map()
for (const [name, array] of entries(this.data)) {
Expand Down
3 changes: 2 additions & 1 deletion bokehjs/src/lib/models/sources/geojson_data_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ export class GeoJSONDataSource extends ColumnarDataSource {

override connect_signals(): void {
super.connect_signals()
this.connect(this.properties.geojson.change, () => this._update_data())
const {geojson} = this.properties
this.on_change(geojson, () => this._update_data())
}

protected _update_data(): void {
Expand Down
5 changes: 2 additions & 3 deletions bokehjs/src/lib/models/tiles/tile_source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,10 @@ export abstract class TileSource extends Model {
}))
}

tiles: Map<string, Tile>
readonly tiles: Map<string, Tile> = new Map()

override initialize(): void {
super.initialize()
this.tiles = new Map()
this._normalize_case()
}

Expand Down Expand Up @@ -86,7 +85,7 @@ export abstract class TileSource extends Model {
}

protected _clear_cache(): void {
this.tiles = new Map()
this.tiles.clear()
}

tile_xyz_to_key(x: number, y: number, z: number): string {
Expand Down
8 changes: 1 addition & 7 deletions bokehjs/src/lib/models/tools/tool_proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,9 @@ export class ToolProxy<T extends Tool> extends Model {
}))
}

do: Signal0<this>
readonly do = new Signal0(this, "do")

// Operates all the tools given only one button

get underlying(): Tool {
return this.tools[0]
}
Expand Down Expand Up @@ -91,11 +90,6 @@ export class ToolProxy<T extends Tool> extends Model {
return tool.visible
}

override initialize(): void {
super.initialize()
this.do = new Signal0(this, "do")
}

override connect_signals(): void {
super.connect_signals()
this.connect(this.do, () => this.doit())
Expand Down